Skip to content

Core Concepts

Build-Time vs Runtime

Prepare scripts run during the build process, not at runtime:

nuxt dev/build → Prepare scripts run → Nuxt builds your app → App runs

Scripts run once per build, so an API call or a database query in a prepare script costs build time, never request time, and what the app ships is the result rather than the code that produced it.

The Problem Nuxt Prepare Solves

Nuxt's configuration file (nuxt.config.ts) doesn't support async operations. This means you can't:

ts
// ❌ This doesn't work in nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    apiUrl: await fetchApiUrl() // Error: top-level await
  }
})

Nuxt Prepare fills this gap by running async code before the configuration is finalized.

How It Works

1. Script Execution

When Nuxt builds your app, prepare scripts are executed in order (or in parallel if configured). Each script returns a result that can modify your Nuxt configuration or pass data to your app.

Scripts from extended layers run before the ones your own project lists, so your project has the last word – its result is merged over theirs. Where several layers list the same script path, it runs once, at the position the highest-priority layer gives it.

A result is merged over nuxt.config.ts rather than under it, so a key a script returns overrides the value already in place. Arrays are the exception: they are concatenated rather than replaced.

2. Generated Files

The module generates files in .nuxt/module/:

nuxt-prepare.mjs – Exported state values:

ts
// Generated by nuxt-prepare
export const todo = {
  "id": 1,
  "title": "Learn Nuxt Prepare"
}

nuxt-prepare.d.ts – Type definitions:

ts
// Generated by nuxt-prepare
export declare const todo: {
  "id": 1,
  "title": "Learn Nuxt Prepare"
}
export type Todo = typeof todo

Both files are written by serializing the state, so the declaration carries the literal values rather than widened ones – todo.id is 1, not number.

3. Module Alias

The generated files are available via the #nuxt-prepare alias, which works in:

  • Nuxt app – Components, composables, pages, layouts
  • Nitro server – API routes, middleware, server utilities
ts
// Works everywhere
import { todo } from '#nuxt-prepare'

State Serialization

State values are JSON-serialized during code generation. This means:

  • ✅ Objects, arrays, strings, numbers, booleans
  • ❌ Functions, classes, symbols, undefined, null
// ✅ This works
state: {
  config: { api: 'https://api.example.com' },
  items: [1, 2, 3]
}

// ❌ This doesn't work
state: {
  handler: () => console.log('hello'), // Functions are lost
  data: undefined, // The key is dropped entirely
  fallback: null // So is this
}

Return Options

Prepare scripts can return:

  • state – Pass build-time data as importable constants via #nuxt-prepare
  • runtimeConfig – Set runtime configuration accessible via useRuntimeConfig()
  • appConfig – Set app configuration accessible via useAppConfig()

See Runtime & App Config for detailed guidance on when to use each option.

Released under the MIT License.