Vue cookbook · Beginner

Manage configuration and secrets with Nuxt runtime config

API keys end up in the client bundle, and changing a URL requires a rebuild.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Declare configuration in runtimeConfig: top-level keys are server-only, keys under public reach the browser. Override values at runtime with NUXT_ environment variables, so one build runs in every environment.

Solution

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    stripeSecretKey: "",                                   // NUXT_STRIPE_SECRET_KEY (server only)
    sessionPassword: "",                                   // NUXT_SESSION_PASSWORD
    public: {
      apiBase: "/api",                                     // NUXT_PUBLIC_API_BASE
      sentryDsn: "",                                       // NUXT_PUBLIC_SENTRY_DSN
    },
  },
});

declare function defineNuxtConfig(config: unknown): unknown;
// server/api/checkout.post.ts (server: full config)
export default defineEventHandler(async (event) => {
  const { stripeSecretKey } = useRuntimeConfig(event);
  if (!stripeSecretKey) throw createError({ statusCode: 500, statusMessage: "Payments not configured" });
  return { ok: true };
});

// app/composables/useApi.ts (client and server: public config only)
export const useApi = () => $fetch.create({ baseURL: useRuntimeConfig().public.apiBase });

Pitfalls

  • Putting secrets under public, which serializes them into every page.
  • Reading process.env directly in app code; it differs between build time and runtime.
  • Forgetting that only keys declared in runtimeConfig can be overridden by NUXT_ variables.

Variations

  • appConfig (app.config.ts) is for build-time, non-secret UI configuration like theme colours.
  • Validate required runtime config at server startup with a Nitro plugin.

Further reading: Runtime config

Reference: https://nuxt.com/docs/4.x/guide/going-further/runtime-config

More Vue recipes

Was this page helpful?