1

I'm having a problem with my mongodb connection string in my nextjs CRUD application in production. I followed this guide: https://www.mongodb.com/developer/how-to/nextjs-building-modern-applications/

And I read about environment variables here: https://nextjs.org/docs/basic-features/environment-variables Giving me the idea that I should be able to safely store my connection string as an environment variable without exposing it to the browser, given I should only need to use it server side?

It works perfectly fine when I run the application locally. But in production (azure app service) the connection string appears undefined unless I expose it to the browser by adding the "NEXT_PUBLIC_" prefix to the variable.

Is it safe to expose this variable / Is there something I should do differently to make it work without exposing it / Is there another approach that should be taken entirely?

My database.js:

import { MongoClient } from 'mongodb';
import nextConnect from 'next-connect';

const client = new MongoClient(process.env.DB_CONNECTION_STRING, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

async function database(req, res, next) {
  await client.connect();
  req.dbClient = client;
  req.db = client.db('Loggen');
  return next();
}

const middleware = nextConnect();

middleware.use(database);

export default middleware;
Rekkert
  • 43
  • 5
  • _"the connection string appears undefined unless I expose it to the browser"_ - Then shouldn't you investigate why the variable is being used on the browser? Are you using the database connection anywhere on client-side code? This might indicate there's a problem with how you're using it. – juliomalves Jan 08 '22 at 16:39

1 Answers1

0

You should not expose env variables.

A) create .env.local file in your project and set up local env variables. (normally all env files are ignored: check gitignore file)

B) You define your vercel .env variables (with the same values for connection)

C) As discussed here, you should follow this example, check how they manage connection (it's an official example), to avoid connection duplication and errors.

D) remember, that your .env variables are accessible only server-side. So, if you like, you can transfer them to client-side but it's not recommended

Your database.js (in example: mongodb.js) should be:

import { MongoClient } from 'mongodb';

const MONGODB_URI = process.env.mongoApiUrl;
const MONGODB_DB = process.env.MONGODB_DB;

// check the MongoDB URI
if (!MONGODB_URI) {
    throw new Error('Define the MONGODB_URI environmental variable');
}

// check the MongoDB DB
if (!MONGODB_DB) {
    throw new Error('Define the MONGODB_DB environmental variable');
}

let cachedClient = null;
let cachedDb = null;

export async function connectToDatabase() {
    // check the cached.
    if (cachedClient && cachedDb) {
        // load from cache
        return {
            client: cachedClient,
            db: cachedDb,
        };
    }

    // set the connection options
    const opts = {
        useNewUrlParser: true,
        useUnifiedTopology: true,
    };

    // Connect to cluster
    let client = new MongoClient(MONGODB_URI, opts);
    await client.connect();
    let db = client.db(MONGODB_DB);

    // set cache
    cachedClient = client;
    cachedDb = db;

    return {
        client: cachedClient,
        db: cachedDb,
    };
}

And better not to use your approach with next-connect, it will create big amount of connections.

illia chill
  • 1,652
  • 7
  • 11
  • B) Yeah I already have my "production env variables" as github secrets and grab them with a github action and docker, is this the equivalent to the vercel stuff you are linking or is it something different? – Rekkert Jan 07 '22 at 09:25
  • A) I use a gitignored .env.local and a non ignored .env that is populated during build time e.g.: DB_USERNAME=$DB_USERNAME – Rekkert Jan 07 '22 at 09:27