Nuxt Config Environment Overrides

Nuxt Config Environment Overrides

I came across a problem when trying to set up local-only configuration in a Nuxt application. These local Nuxt config are not simply environment variables, but rather configuration that overrides specific Nuxt settings (like ports, proxies, dev server options) that may not be needed to be included to version control.

The official Nuxt documentation mentions environment-specific overrides using $development and $production keys, but these are still within the committed nuxt.config.ts file.

https://nuxt.com/docs/4.x/getting-started/configuration#environment-overrides

However, this doesn't solve the problem of having local-only configuration, we could import a config file that is gitignored and put it on per-environment overrides, but
if we do that, it would fail in CI/CD pipelines where the file doesn't exist and it's not even necessary to have it there just make the build work on CI/CD. (I hope that makes sense)

import devConfig from './.config/nuxt.config.local`

export default defineNuxtConfig({
  $development: {
    ...devConfig
  }
})

This creates issues when:

  • Each developer needs different local settings (ports, hosts, HMR configs)
  • You want to override complex nested objects (Vite server config, devServer settings) when you work with tunnels, proxies, etc. where each dev has different or multiple tunnel URLs.

Solution

My initial solution was to create a nuxt.config.local.ts file that is ignored in version control, and dynamically import it in the main nuxt.config.ts file and use the Environment Overrides provided by Nuxt.

Step 1: Create Local Config

  1. Create a local override file. I placed it in .config/ config folder. since Nuxt's TSConfig includes it by default. That way I can get typings on the Nuxt Config.
// <project-root>/.config/nuxt.config.local.ts
import type { NuxtConfig } from 'nuxt/schema'

export default defineNuxtConfig({
  devServer: {
    // Local dev server port.
    port: 3005, 
  },
   vite: {
    server: {
      // If you want to access local dev with a local domain.
      allowedHosts: [
        'random1-given-by-tunnel.example.com',
        'something-else.example.dev'
      ],
    },
  },
})

Step 2: Update Main nuxt.config.ts

// nuxt.config.ts

// Helper to dynamically import local config file
async function loadConfigFile(filePath: string) {
  try {
    return (await import(filePath)).default;
  }
  catch {
  }
}

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },
  appConfig: {},
  runtimeConfig: {
  },

  // Environment Overrides
  $development: {
    // some development defaults
    modules: ["@nuxtjs/html-validator"],

    // Load local config overrides that are not needed to be committed.
    ...await loadConfigFile('./.config/nuxt.config.local.ts'),
  },
});

And that's it!

Our dynamic import function will try to load the local config file:

async function loadConfigFile(filePath: string) {
  try {
    return (await import(filePath)).default;
  }
  catch {
  }
}

What do you think? I would like to hear your thoughts, suggestions or alternative for this scenario!

References

Publications

This is also published on my Github Gist: https://gist.github.com/markterence/0de66216963582f44c1a99998e9f309b


You'll only receive email when they publish something new.

More from Mark Terence
All posts