How do I load environment variables in Nitro?

HEAD
4df7aabfeat: `nitro deploy` command (#4042)
This post might have stale content, as HEAD is 60 commits ahead.

how do i load env vars? dotenv? or nitro has auto support for it

Avatar of anthropic/claude-opus-4.6
Claude Opus 4.6
commented

Here's the full picture:


##Nitro has built-in support for environment variables — no need to manually install or configure dotenv.

There are two distinct mechanisms:

###1. .env file loading (build-time / dev / preview)

Nitro uses c12 under the hood, which has built-in dotenv support. The behavior depends on the mode:

  • In development (dev: true), Nitro automatically loads .env and .env.local files from your project root.
    Source: src/config/loader.ts line 81:

    const _dotenv = opts.dotenv ?? (configOverrides.dev && { fileName: [".env", ".env.local"] });
    
  • In preview mode (nitro preview), it loads .env.preview, .env.production, and .env (in that priority order).
    Source: src/preview.ts lines 111–115:

    const env = await loadDotenv({
      cwd: root,
      fileName: [".env.preview", ".env.production", ".env"],
    });
    
  • In production, .env files are NOT loaded. You're expected to set environment variables through your platform (Vercel, Cloudflare, etc.).

###2. Runtime config + env variable mapping (runtime)

This is the main way to use env vars at runtime. Nitro automatically maps process.env variables to your runtime config keys using a naming convention.

Source: src/runtime/internal/runtime-config.ts:

function getRuntimeConfig() {
  const env = globalThis.process?.env || {};
  applyEnv(runtimeConfig, {
    prefix: "NITRO_",
    altPrefix: runtimeConfig.nitro?.envPrefix ?? env?.NITRO_ENV_PREFIX ?? "_",
    envExpansion: Boolean(runtimeConfig.nitro?.envExpansion ?? env?.NITRO_ENV_EXPANSION ?? false),
  });
  return runtimeConfig;
}

How it works:

  • Define keys in your runtimeConfig in nitro.config.ts.
  • At runtime, Nitro checks for env vars with the NITRO_ prefix (or a custom altPrefix via NITRO_ENV_PREFIX).
  • The key is converted to UPPER_SNAKE_CASE.

Example:

// nitro.config.ts
export default defineNitroConfig({
  runtimeConfig: {
    secretKey: "default-value", // → overridden by NITRO_SECRET_KEY
    database: {
      host: "localhost",       // → overridden by NITRO_DATABASE_HOST
    },
  },
});

Then in your handler:

const config = useRuntimeConfig();
console.log(config.secretKey);       // reads NITRO_SECRET_KEY or falls back to "default-value"
console.log(config.database.host);   // reads NITRO_DATABASE_HOST or falls back to "localhost"

###3. Env expansion (experimental)

You can enable {{VAR_NAME}} expansion inside runtime config string values:

// nitro.config.ts
export default defineNitroConfig({
  experimental: { envExpansion: true },
  runtimeConfig: {
    dbUrl: "postgres://{{DB_HOST}}:{{DB_PORT}}/mydb",
  },
});

This replaces {{DB_HOST}} with process.env.DB_HOST at runtime (source).

###TL;DR

Mode.env files loadedMechanism
Dev.env, .env.localAutomatic via c12
Preview.env.preview, .env.production, .envAutomatic via c12
Production❌ NoneSet env vars on your platform

At runtime (all modes), env vars prefixed with NITRO_ automatically override matching runtimeConfig keys. No dotenv package needed — it's all built in. (dotenv is listed as an optional peer dependency, only used if c12 needs it internally.)


END OF POST

How do I load environment variables in Nitro? — nitrojs/nitro