Environment Variables and Application Configuration

Applications should not hardcode database connection strings throughout their source code. Environment-based configuration makes it easier to separate development, testing, staging, and production settings.

Example project structure

my-node-app/
 src/
 db.js
 server.js
 .env
 .gitignore
 package.json

The exact structure depends on the application. The important principle is that sensitive configuration is managed outside committed application source code.

Example environment file

MONGODB_URI=mongodb://127.0.0.1:27017/learning
NODE_ENV=development

This example assumes a local development server without authentication. For an authenticated deployment, use an appropriate connection string and store the credentials securely.

Prevent secrets from entering source control

Add the environment file to .gitignore:

.env
.env.local
.env.*.local

If a secret was already committed, adding the file to .gitignore does not remove it from Git history or invalidate the exposed credential. Rotate the credential and follow the repository's secret-remediation process.

Loading variables in Node.js

Modern Node.js versions support loading environment files through built-in command-line options. For projects using a dotenv package, configuration can be loaded explicitly.

For example, install dotenv if your project uses that approach:

npm install dotenv

Then load the configuration before accessing the environment variable:

import dotenv from "dotenv";

dotenv.config();

const uri = process.env.MONGODB_URI;

if (!uri) {
 throw new Error("MONGODB_URI is missing");
}

Alternatively, configure your runtime or hosting platform to supply environment variables directly. Avoid loading the same environment file unnecessarily in many modules.

Next.js considerations

For a Next.js application, database access should occur in server-side code. Keep the MongoDB URI in a server-only variable such as MONGODB_URI.

Do not use NEXT_PUBLIC_MONGODB_URI. Variables with the NEXT_PUBLIC_ prefix are intended for values that can be exposed to browser-side code.

In the Pages Router, database operations may be performed in API routes or other server-side code. In the App Router, they may be performed in appropriate server-side route handlers or server components, depending on the architecture.

Production configuration

Production applications should obtain secrets from an appropriate secret manager or the hosting platform's protected environment configuration. Limit access to the credentials, rotate them when necessary, and avoid printing connection strings in logs.

Environment variables help organize configuration; they do not automatically encrypt every value or prevent access by processes that have permission to read them.

Never expose a database secret to the browser

A MongoDB connection URI may grant direct database access. Keep it on the server, restrict database privileges, and never return it in an API response or include it in browser bundles.

Validate database configuration safely
const mongodbUri = process.env.MONGODB_URI;

if (typeof mongodbUri !== "string" || mongodbUri.length === 0) {
 throw new Error("Missing required environment variable: MONGODB_URI");
}

export const databaseConfig = {
 uri: mongodbUri
};
💡 The module validates the required environment variable and exports a configuration object. It does not log the URI. In a real application, keep this module server-only and ensure the runtime has loaded or supplied the environment variable before importing it.
Key Takeaways
  • Environment variables separate configuration from source code.
  • A .gitignore entry prevents ordinary future tracking but does not erase previously committed secrets.
  • Node.js can read environment variables through process.env.
  • Next.js database operations should use server-side code.
  • Environment variables are not a replacement for access control and secret management.
Knowledge Check

Why should a MongoDB connection string containing credentials not use the `NEXT_PUBLIC_` prefix in Next.js?