Nuxt Environment Variables and Configuration — Runtime Config, .env, and Per-Environment Settings
In this tutorial, you will learn about Nuxt Environment Variables and Configuration. We cover key concepts, practical examples, and best practices to help you master this topic.
Learn Nuxt environment variables and configuration — manage runtime config, private and public variables, .env files, and per-environment settings for development and production.
In this lesson, you'll understand how to use Nuxt's runtime config system to manage environment-specific settings securely across development, staging, and production.
What You'll Learn
How to define runtime configuration in nuxt.config.ts, use public and private runtime config, work with .env files and environment variables, access config in composables and server routes, and validate configuration at startup.
Why It Matters
Hardcoded configuration values break when you deploy to different environments. A proper config system separates code from environment, keeps secrets secure, and lets you change behavior without modifying source code.
Real-World Use
A fintech application uses Nuxt runtime config to manage 40+ environment variables across development, staging, and production — API keys, database URLs, and feature flags — with validation that catches misconfiguration before deployment.
flowchart LR
A[.env File] --> B[Nuxt Config]
C[Shell Env Vars] --> B
B --> D[Public Config]
B --> E[Private Config]
D --> F[Client-side]
E --> G[Server-side Only]
F --> H[API Base URL]
F --> I[Feature Flags]
G --> J[API Keys]
G --> K[Database URLs]
style A fill:#00dc82,color:#fff
Runtime Config in nuxt.config.ts
Define configuration values that can change between environments:
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
// Private keys (server-side only)
apiSecret: '',
databaseUrl: '',
jwtSecret: '',
// Public config (accessible on client and server)
public: {
apiBase: 'https://api.example.com',
siteUrl: 'https://example.com',
appName: 'My Nuxt App',
version: '1.0.0',
features: {
darkMode: true,
beta: false,
analytics: true
}
}
}
});
Expected output: Configuration with private values that are never exposed to the client and public values accessible everywhere.
Using Environment Variables
Override runtime config values with environment variables:
# .env (never committed to version control)
NUXT_API_SECRET=super-secret-key
NUXT_DATABASE_URL=postgresql://localhost:5432/mydb
NUXT_JWT_SECRET=jwt-secret-value
NUXT_PUBLIC_API_BASE=https://api.production.com
NUXT_PUBLIC_SITE_URL=https://example.com
Nuxt automatically maps environment variables to runtime config. The pattern is:
NUXT_+ uppercase config path with underscores- Example:
runtimeConfig.public.apiBase→NUXT_PUBLIC_API_BASE
Expected output: Environment variables override the default values in nuxt.config.ts without changing source code.
Accessing Config in Components
Use useRuntimeConfig to access configuration:
<script setup>
const config = useRuntimeConfig();
// Public config is available everywhere
const apiBase = config.public.apiBase;
const appName = config.public.appName;
const features = config.public.features;
// Private config is undefined on the client
const apiSecret = config.apiSecret; // undefined in browser
</script>
<template>
<div>
<h1>{{ appName }} v{{ config.public.version }}</h1>
<div v-if="features.darkMode">
<ThemeToggle />
</div>
<div v-if="features.beta" class="beta-banner">
Beta feature preview
</div>
</div>
</template>
Expected output: Public config values render in the template. Private values are undefined on the client, keeping secrets secure.
Accessing Config in Server Routes
Private config is fully available in server routes:
// server/api/external-data.ts
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig(event);
// Private config — accessible only on server
const apiSecret = config.apiSecret;
const databaseUrl = config.databaseUrl;
// Use config for external API call
const data = await $fetch('https://external-api.com/data', {
headers: {
Authorization: `Bearer ${apiSecret}`
}
});
// Use config for database connection
const db = await connectToDatabase(databaseUrl);
return {
data,
source: 'protected'
};
});
Expected output: Server routes can access private configuration values, making authenticated API calls and database connections without exposing secrets to the client.
Per-Environment Configuration Files
Create separate config files for different environments:
# .env.development
NUXT_PUBLIC_API_BASE=http://localhost:3000/api
NUXT_PUBLIC_SITE_URL=http://localhost:3000
# .env.staging
NUXT_PUBLIC_API_BASE=https://staging-api.example.com
NUXT_PUBLIC_SITE_URL=https://staging.example.com
NUXT_PUBLIC_FEATURES_BETA=true
# .env.production
NUXT_PUBLIC_API_BASE=https://api.example.com
NUXT_PUBLIC_SITE_URL=https://example.com
NUXT_API_SECRET=${PROD_API_SECRET}
# Load the correct file based on environment
# development (default)
nuxt dev
# staging
NODE_ENV=staging npx nuxt build --dotenv .env.staging
# production
npx nuxt build --dotenv .env.production
Expected output: Different environments use different configuration files, enabling environment-specific API endpoints, feature flags, and credentials.
Config Validation
Validate required configuration on startup:
// server/middleware/config-check.ts
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig(event);
const requiredPrivate = ['apiSecret', 'jwtSecret'];
const missingPrivate = requiredPrivate.filter(
key => !config[key]
);
if (missingPrivate.length > 0) {
console.error(
`Missing private config: ${missingPrivate.join(', ')}`
);
}
const requiredPublic = ['apiBase', 'siteUrl'];
const missingPublic = requiredPublic.filter(
key => !config.public[key]
);
if (missingPublic.length > 0) {
console.error(
`Missing public config: ${missingPublic.join(', ')}`
);
}
});
Expected output: Missing configuration is detected at startup with clear error messages, preventing runtime failures caused by unset variables.
Build-Time vs Runtime Config
Understanding when config values are resolved:
// nuxt.config.ts
export default defineNuxtConfig({
// Build-time config — embedded in the bundle
app: {
baseURL: '/app/',
buildAssetsDir: '/_nuxt/'
},
// Runtime config — resolved at runtime, overrideable
runtimeConfig: {
public: {
apiBase: 'https://api.example.com'
}
}
});
<script setup>
// build-time: available during build, cannot change without rebuild
const baseURL = useRuntimeConfig().app.baseURL;
// runtime: can change by setting environment variables
const apiBase = useRuntimeConfig().public.apiBase;
</script>
Expected output: Build-time config is embedded in the JavaScript bundle. Runtime config can be overridden with environment variables without rebuilding the application.
Common Mistakes
Putting secrets in public runtime config: Public config values are sent to the browser in the rendered HTML. Never put API keys, database passwords, or authentication tokens in
public.Forgetting the NUXT_ prefix convention: Environment variables must start with
NUXT_to be automatically mapped to runtime config. A variable namedAPI_SECRETis ignored.Not providing default values: If a runtime config key has no default in
nuxt.config.tsand no environment variable is set, it'sundefined. Always provide defaults or validate that required values exist.Using process.env directly in components:
process.envvalues are inlined at build time and don't support runtime overrides. Always useuseRuntimeConfigfor values that need to change per environment.Committing .env files to version control: The
.envfile often contains secrets. Add it to.gitignore. Use.env.exampleas a template that documents required variables without real values.
Practice Questions
What is the difference between public and private runtime config? Answer: Public config is accessible on both client and server, rendered into the HTML. Private config is only available in server routes and Nitro contexts — never exposed to the browser.
How does Nuxt map environment variables to runtime config? Answer: It follows the pattern
NUXT_+ uppercase config path. For example,runtimeConfig.public.apiBasemaps toNUXT_PUBLIC_API_BASE. Underscores replace dots in the path.When should you use build-time config instead of runtime config? Answer: Use build-time config for values that cannot change after the application is built (base URL, build assets directory). Use runtime config for environment-specific values that need per-deployment control.
How do you validate required configuration at startup? Answer: Create a server middleware or Nitro plugin that checks required config keys and logs warnings or throws errors if values are missing.
Challenge
Build a multi-environment deployment system with: separate .env.development, .env.staging, and .env.production files, a validation script that checks all required variables exist before building, feature flags controlled by runtime config (dark mode, beta features, analytics), and a /api/config-check endpoint that returns the health of all configuration.
Mini Project
Create a configuration management system for a Nuxt app with: runtime config for API base URL, analytics ID, and feature flags, separate .env files for dev, staging, and production, a config validation plugin that runs on startup, a settings page that displays current config (public only) in development mode, a server route that uses private config to authenticate with an external API, and a .env.example file documenting all required variables.
FAQ
What's Next
Learn about Nuxt Deployment to deploy your Nuxt application to production on static hosting, Node.js servers, and Serverless platforms.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro