配置系统

Nuxt 自带合理默认值,大多数项目只改几项配置。nuxt.config.ts 是唯一的真相源:模块、环境覆盖、runtimeConfig、Vite/Nitro 透传、Vue 开关全写在这里。

nuxt.config.ts

export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ['@pinia/nuxt', '@nuxtjs/tailwindcss'],
  css: ['~/assets/css/main.css'],
})

defineNuxtConfig 全局可用(不需要 import),并且有完整的 TypeScript 补全。

按环境覆盖

Nuxt 会在合并前优先读取 $development$production$env.*

export default defineNuxtConfig({
  $production: {
    routeRules: {
      '/**': { isr: true },
    },
  },
  $development: {
    devtools: { enabled: true },
  },
  $env: {
    staging: { app: { baseURL: '/staging/' } },
  },
})

构建时通过 nuxt build --envName staging 指定环境。背后由 c12 实现。

runtimeConfigapp.config 的区别

两者都能暴露配置值,但解决的问题不同:

关注点 runtimeConfig app.config
定义位置 nuxt.config.ts app.config.ts
支持环境变量覆盖 是(NUXT_*
客户端可访问 只有 public 下的键 完整打包
支持非基础 JS 类型
响应式
适合用来放 密钥、URL、Token 主题、站点元信息、开关

runtimeConfig

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    apiSecret: '',          // 仅服务端
    public: {
      apiBase: '/api',      // 暴露给客户端
    },
  },
})

通过环境变量覆盖:

NUXT_API_SECRET=prod_secret
NUXT_PUBLIC_API_BASE=https://api.example.com

使用 composable 读取:

<script setup lang="ts">
const { apiSecret, public: { apiBase } } = useRuntimeConfig()
</script>

在客户端,apiSecret 会是 undefined

app.config

// app/app.config.ts
export default defineAppConfig({
  title: 'Hello Nuxt',
  theme: { dark: true, colors: { primary: '#3b82f6' } },
})
<script setup lang="ts">
const appConfig = useAppConfig()
</script>

app.config 支持 HMR —— 改主题会立即生效。

TypeScript

Nuxt 会自动生成 .nuxt/tsconfig.json,项目的 tsconfig.json 继承它,无需手动配置。

需要自定义时:

export default defineNuxtConfig({
  typescript: {
    strict: true,
    typeCheck: true, // 构建时跑 vue-tsc
  },
})

给 Vite / Nitro / PostCSS 传选项

Nuxt 不会 读取外部的 vite.config.ts / nitro.config.ts,都要通过 Nuxt 的 key 透传:

export default defineNuxtConfig({
  vite: {
    plugins: [/* … */],
  },
  nitro: {
    preset: 'node-server',
    compressPublicAssets: true,
  },
  postcss: {
    plugins: {
      'postcss-nested': {},
    },
  },
})

Vue 相关开关

export default defineNuxtConfig({
  vue: {
    propsDestructure: true, // 实验特性
  },
})

也可以直接通过 vite.vue@vitejs/plugin-vue 传参。

应用级 head

要应用到所有页面的静态标签放在 app.head

export default defineNuxtConfig({
  app: {
    head: {
      titleTemplate: '%s · Nuxt 小册',
      htmlAttrs: { lang: 'zh-CN' },
      link: [{ rel: 'icon', href: '/favicon.ico' }],
    },
  },
})

页面级、动态标签用 useHead() —— 详见 SEO 那章。

怎么选?

  • 项目里的静态开关?app.config
  • 密钥或环境相关?runtimeConfig
  • 构建期转换?nuxt.configvite / nitro key)
  • 按环境切换?$development / $production / $env

一个文件,四个旋钮,足够把项目跑起来。

配置系統

Nuxt 內建合理預設,多數專案只需調整數個選項。nuxt.config.ts 是唯一真相來源:模組、環境覆寫、runtimeConfig、Vite/Nitro 轉發、Vue 開關皆於此設定。

nuxt.config.ts

export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ['@pinia/nuxt', '@nuxtjs/tailwindcss'],
  css: ['~/assets/css/main.css'],
})

defineNuxtConfig 全域可用(無需 import),並提供完整 TypeScript 補全。

依環境覆寫

Nuxt 會在合併前優先讀取 $development$production$env.*

export default defineNuxtConfig({
  $production: {
    routeRules: {
      '/**': { isr: true },
    },
  },
  $development: {
    devtools: { enabled: true },
  },
  $env: {
    staging: { app: { baseURL: '/staging/' } },
  },
})

建置時用 nuxt build --envName staging 指定環境。底層由 c12 實作。

runtimeConfigapp.config 的差異

兩者皆可暴露設定值,但用途不同:

關注點 runtimeConfig app.config
定義位置 nuxt.config.ts app.config.ts
支援環境變數覆寫 是(NUXT_*
客戶端可存取 public 下的鍵 完整打包
支援非基本 JS 型別
響應式
適合擺放 金鑰、URL、Token 主題、站點中繼資料、旗標

runtimeConfig

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    apiSecret: '',          // 僅伺服器端
    public: {
      apiBase: '/api',      // 曝露給客戶端
    },
  },
})

以環境變數覆寫:

NUXT_API_SECRET=prod_secret
NUXT_PUBLIC_API_BASE=https://api.example.com

以 composable 讀取:

<script setup lang="ts">
const { apiSecret, public: { apiBase } } = useRuntimeConfig()
</script>

客戶端取到的 apiSecret 會是 undefined

app.config

// app/app.config.ts
export default defineAppConfig({
  title: 'Hello Nuxt',
  theme: { dark: true, colors: { primary: '#3b82f6' } },
})
<script setup lang="ts">
const appConfig = useAppConfig()
</script>

app.config 支援 HMR —— 改主題會立刻生效。

TypeScript

Nuxt 會自動產生 .nuxt/tsconfig.json,專案 tsconfig.json 繼承它,毋須手動設定。

需要自訂時:

export default defineNuxtConfig({
  typescript: {
    strict: true,
    typeCheck: true, // 建置時執行 vue-tsc
  },
})

向 Vite / Nitro / PostCSS 傳選項

Nuxt 不會 讀取外部的 vite.config.ts / nitro.config.ts,需透過 Nuxt 的 key 轉發:

export default defineNuxtConfig({
  vite: {
    plugins: [/* … */],
  },
  nitro: {
    preset: 'node-server',
    compressPublicAssets: true,
  },
  postcss: {
    plugins: {
      'postcss-nested': {},
    },
  },
})

Vue 相關開關

export default defineNuxtConfig({
  vue: {
    propsDestructure: true, // 實驗特性
  },
})

也可直接透過 vite.vue@vitejs/plugin-vue 傳參。

應用層級 head

欲套用至所有頁面的靜態標籤放在 app.head

export default defineNuxtConfig({
  app: {
    head: {
      titleTemplate: '%s · Nuxt 小冊',
      htmlAttrs: { lang: 'zh-Hant' },
      link: [{ rel: 'icon', href: '/favicon.ico' }],
    },
  },
})

頁面層級、動態標籤改用 useHead() —— 詳見 SEO 章節。

如何抉擇?

  • 專案內的靜態旗標?app.config
  • 金鑰或環境相關?runtimeConfig
  • 建置期轉換?nuxt.configvite / nitro key)
  • 按環境切換?$development / $production / $env

一個檔案、四個旋鈕,足以把專案跑起來。

Configuration

Nuxt ships with sane defaults, so most teams only tweak a handful of options. nuxt.config.ts is the single source of truth: modules, env overrides, runtime config, Vite/Nitro passthrough, and Vue-specific flags all live here.

nuxt.config.ts

export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ['@pinia/nuxt', '@nuxtjs/tailwindcss'],
  css: ['~/assets/css/main.css'],
})

defineNuxtConfig is globally available (no import needed) and provides full TypeScript completion.

Per-environment overrides

Nuxt reads $development, $production, and named $env.* keys before merging into the root config:

export default defineNuxtConfig({
  $production: {
    routeRules: {
      '/**': { isr: true },
    },
  },
  $development: {
    devtools: { enabled: true },
  },
  $env: {
    staging: { app: { baseURL: '/staging/' } },
  },
})

Select an env at build time with nuxt build --envName staging. The mechanism is powered by c12.

runtimeConfig vs app.config

Both expose values, but they solve different problems:

Concern runtimeConfig app.config
Defined in nuxt.config.ts app.config.ts
Overridable by env vars Yes (NUXT_*) No
Available on client Only public keys Fully bundled
Supports non-primitive JS types No Yes
Reactive Yes Yes
Use it for Secrets, URLs, keys Theme, site metadata, flags

runtimeConfig

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    apiSecret: '',          // server-only
    public: {
      apiBase: '/api',      // exposed to client
    },
  },
})

Override via environment variables:

NUXT_API_SECRET=prod_secret
NUXT_PUBLIC_API_BASE=https://api.example.com

Read it with the composable:

<script setup lang="ts">
const { apiSecret, public: { apiBase } } = useRuntimeConfig()
</script>

apiSecret is undefined on the client.

app.config

// app/app.config.ts
export default defineAppConfig({
  title: 'Hello Nuxt',
  theme: { dark: true, colors: { primary: '#3b82f6' } },
})
<script setup lang="ts">
const appConfig = useAppConfig()
</script>

HMR works for app.config — theme changes update instantly during dev.

TypeScript

Nuxt generates .nuxt/tsconfig.json automatically and your project tsconfig.json extends it. No manual setup required.

To customize, pass options to Nuxt:

export default defineNuxtConfig({
  typescript: {
    strict: true,
    typeCheck: true, // run vue-tsc during build
  },
})

Passing options to Vite / Nitro / PostCSS

Nuxt intentionally does not read external vite.config.ts / nitro.config.ts. Configure them through Nuxt keys:

export default defineNuxtConfig({
  vite: {
    plugins: [/* … */],
  },
  nitro: {
    preset: 'node-server',
    compressPublicAssets: true,
  },
  postcss: {
    plugins: {
      'postcss-nested': {},
    },
  },
})

Vue-specific knobs

export default defineNuxtConfig({
  vue: {
    propsDestructure: true, // experimental
  },
})

Nuxt also lets you target @vitejs/plugin-vue directly via vite.vue.

App-level head

Static tags that apply to every page live in app.head:

export default defineNuxtConfig({
  app: {
    head: {
      titleTemplate: '%s · Nuxt Book',
      htmlAttrs: { lang: 'en' },
      link: [{ rel: 'icon', href: '/favicon.ico' }],
    },
  },
})

Per-page, dynamic tags belong in useHead() — see the SEO chapter.

When to pick what

  • Quick, static project flag?app.config
  • Secret or env-dependent value?runtimeConfig
  • Build-time transform?nuxt.config (Vite/Nitro keys)
  • Per-env behavior?$development / $production / $env

One file, four knobs, enough to ship.