
# Build

> Bundler selection and build output tuning.

::note
All examples on this page assume the following import in `nitro.config.ts`:

```ts
import { defineConfig } from "nitro";
```
::

### `builder`

- Type: `"rollup"`{lang=ts} | `"rolldown"`{lang=ts} | `"vite"`{lang=ts} | `false`{lang=ts}
- Default: `undefined`{lang=ts} (auto-detected)

Specify the bundler to use for building.

```ts
export default defineConfig({
  builder: "vite",
});
```

When not set, Nitro uses `vite` if your `vite.config` uses the `nitro()` plugin, otherwise `rolldown`. The builder package is resolved from your project (`rolldown` also through your `vite`) and installed on demand when building. In development, if `rolldown` is not installed and no [`rollupConfig`](#rollupconfig) or [`rolldownConfig`](#rolldownconfig) is set, `nitro dev` runs without a builder (`builder: false`) and `nitro build` offers to install it.

Set `builder: false` (experimental) to run the server sources without bundling. `nitro dev` then runs your files directly in an [env-runner](https://github.com/unjs/env-runner) worker, Nitro's virtual modules are served from memory, and a fresh worker starts on each change. [`nitro start`](/docs/cli#nitro-serve) (or `nitro serve`) runs the sources the same way in production mode, without a build step, whatever builder is configured. `nitro preview` only serves a build output. [Prerendering](/docs/prerendering) runs the sources the same way, and is also used by the `vite` builder when `rolldown` is not installed. `nitro build` is not supported yet.

Modules are transformed on demand, like in a bundled build: TypeScript and JSX, `import.meta.*` and [`replace`](#replace) values, [`alias`](#alias), extensionless imports, `raw:`/`text`/`bytes` imports and WebAssembly.

::note
- On Bun, aliases without a file extension (such as `~/utils`) and WebAssembly imports are not resolved yet.
- Files outside the project, its scan dirs and Nitro (such as linked workspace packages) are loaded as-is, without these transforms.
- Bundler options (`rollupConfig`, `rolldownConfig`) and plugins added by modules with the `build:config` hook do not apply. Use [`buildPlugins`](#buildplugins) for plugins.
::

### `buildPlugins`

- Type: `NitroBuildPluginOption[]`{lang=ts}
- Default: `[]`{lang=ts}

Build plugins applied with every [builder](#builder) (`rollup`, `rolldown`, `vite` and `false`). Nested arrays and promises are resolved, falsy entries are skipped.

Plugins use the Rollup plugin interface. Prefer the `resolveId`, `load` and `transform` hooks with a `filter`: they are the ones supported by all builders.

Plugins with `enforce: "pre"` are placed before Nitro's own plugins, the others after them (`enforce: "post"` last). A hook's own `order` takes precedence: several Nitro hooks (such as virtual module resolution) use `order: "pre"`, so use it too for a hook that must run before them.

::note
- Builders differ in what runs around the plugins. `transform` hooks receive TypeScript and JSX untransformed with `rolldown` (it compiles them after the plugins) and for `enforce: "pre"` plugins with `rollup`. With `vite`, Vite's own resolution and transforms run first.
- With `vite`, plugins apply to the `nitro` environment only, as bundler plugins: Vite-specific options and hooks (such as `apply` or `configureServer`) are not supported. Add Vite plugins to Vite's `plugins` instead.
- With `builder: false`, plugins run in [env-runner](https://github.com/unjs/env-runner), which supports only `resolveId`, `load` and `transform` (with a limited plugin context) and warns about other hooks. Hooks only receive JavaScript and TypeScript modules unless their `filter` names other files (by `id` or `moduleType`), and files in `node_modules` only when it names `node_modules`.
::

```ts
export default defineConfig({
  buildPlugins: [
    {
      name: "my-virtual-module",
      resolveId: {
        filter: { id: /^virtual:my-module$/ },
        handler: (id) => `\0${id}`,
      },
      load: {
        filter: { id: /^\0virtual:my-module$/ },
        handler: () => `export default "Hello!"`,
      },
    },
  ],
});
```

Nitro modules can add plugins with `nitro.options.buildPlugins.push(plugin)`.

### `rollupConfig`

Additional rollup configuration.

```ts
export default defineConfig({
  rollupConfig: {
    output: { manualChunks: { vendor: ["lodash-es"] } },
  },
});
```

### `rolldownConfig`

Additional rolldown configuration.

```ts
export default defineConfig({
  rolldownConfig: {
    output: { banner: "/* built with nitro */" },
  },
});
```

### `vite`

Options for the `vite` builder and the `nitro/vite` plugin.

- `path`: The `vite` package to use, as a path or `file://` URL to its directory or entry (same as [`deps.paths.vite`](#deps)). By default, the `nitro/vite` plugin uses the running `vite` and the `vite` builder resolves it from the project root.
- `services`: Additional Vite environments to register as fetchable services, as `{ [name]: { entry } }`. Server environments with an entry (such as `ssr`) are registered automatically.
- `assetsImport`: Enable `?assets` imports for collecting CSS and JS assets from entry points (default: `true`).
- `serverReload`: Reload the dev server (and the browser) when a server-only module changes (default: `true`).

```ts
export default defineConfig({
  vite: {
    path: import.meta.resolve("vite"),
    services: { api: { entry: "./src/api-entry.ts" } },
  },
});
```

### `deps`

Options for the optional dependencies Nitro installs on demand (such as `vite`, `rolldown`, `rollup`, `unstorage`, `db0` or `unenv`).

- `paths`: Explicit packages to use, by package name. Each value is a path or `file://` URL to the package directory or entry. Relative paths resolve against [`rootDir`](/config/directories#rootdir).

By default, these packages are resolved from your project and installed on demand when missing. A framework built on top of Nitro can pass its own copies in `deps.paths` instead, so the versions it depends on are the ones that run. The server bundle uses them too for `unstorage`, `db0` and `unenv`. An explicit package is never installed, and Nitro warns when its version is outside the supported range. Nothing is installed either when [`rootDir`](/config/directories#rootdir) is inside `node_modules` (e.g. a framework using its own package directory): the framework has to declare the packages it uses in its own dependencies or pass them in `deps.paths`.

```ts
export default defineConfig({
  deps: {
    paths: {
      unstorage: import.meta.resolve("unstorage"),
      db0: import.meta.resolve("db0"),
    },
  },
});
```

`deps.paths.vite` is an alias of [`vite.path`](#vite).

### `entry`

Bundler entry point.

```ts
export default defineConfig({
  entry: "./server/entry.ts", // custom entry file
});
```

### `alias`

Path aliases for module resolution.

```ts
export default defineConfig({
  alias: {
    "~utils": "./src/utils",
    "#shared": "./shared",
  },
});
```

With the Vite builder, these aliases apply to every Vite environment. When Vite's `resolve.alias` (from the Vite config or another plugin, with a string `find`) maps the same key to another target, the Nitro target applies only to the `nitro` environment, and other environments (such as `client` and `ssr`) use the Vite target.

### `inject`

Globals to replace with imports when referenced in the bundle. Values are a module id (default export) or a `[id, exportName]` tuple.

Set a global to `false` to remove a default injection (e.g. one added for [`node: false`](#node) builds).

```ts
export default defineConfig({
  inject: {
    Buffer: ["node:buffer", "Buffer"],
    performance: false,
  },
});
```

### `polyfills`

Modules imported for their side effects before the server entry. Prefix an entry with `!` to remove a default polyfill.

[`node: false`](#node) builds add `#nitro/runtime/polyfills/global`, `#nitro/runtime/polyfills/process`, `#nitro/runtime/polyfills/buffer` and `#nitro/runtime/polyfills/timers` by default (e.g. `"!#nitro/runtime/polyfills/timers"` removes the `setImmediate` polyfill).

```ts
export default defineConfig({
  polyfills: ["./polyfills/intl.ts"],
});
```

### `builtinModules`

Modules provided by the target runtime, such as `cloudflare:workers` or `node:fs` on Deno. Imports of these ids are kept as-is in the output.

Builtin modules are never bundled, traced, or copied to the output, so only list modules that the runtime itself provides. To keep an npm package out of the bundle, use [`traceDeps`](#tracedeps) instead. Node.js builtins are handled automatically when [`node`](#node) is `true`.

Prefix an entry with `!` to remove a default (e.g. one added by a preset).

```ts
export default defineConfig({
  builtinModules: ["cloudflare:workers"],
});
```

::note
Presets also add default `alias`, `inject`, `polyfills`, and `builtinModules` entries (for example, Cloudflare and Deno map Node.js builtins they support natively). Your own values in these options always take precedence.

The `unenv` option is deprecated. Presets passed to it still apply, after preset defaults and before your own options.
::

### `minify`

- Default: `false`{lang=ts}

Minify bundle.

Some presets (especially worker runtimes) enable minification by default. Set `minify: false` when debugging production, worker, or edge builds so stack traces stay readable. 

```ts
export default defineConfig({
  minify: true, // minify production bundle
});
```

```ts
export default defineConfig({
  minify: false, // easier to debug workers / edge bundles
});
```

### `inlineDynamicImports`

- Default: `false`{lang=ts}

Bundle all code into a single file instead of creating separate chunks per route.

When `false`, each route handler becomes a separate chunk loaded on-demand. When `true`, everything is bundled together. Some presets enable this by default.

```ts
export default defineConfig({
  inlineDynamicImports: true, // single output file
});
```

### `sourcemap`

- Default: `false`{lang=ts}

Enable source map generation. See [options](https://rollupjs.org/configuration-options/#output-sourcemap).

```ts
export default defineConfig({
  sourcemap: true, // generate .map files
});
```

### `node`

- Default: `true`{lang=ts}

Specify whether the build is used for Node.js or not. If set to `false`, nitro adds default [`alias`](#alias), [`inject`](#inject) and [`polyfills`](#polyfills) entries that polyfill Node.js globals and built-in modules (using [unenv](https://github.com/unjs/unenv)), and adjusts its behavior.

Node.js built-in modules that the target runtime does not provide (e.g. `node:inspector` on Cloudflare) are polyfilled with [unenv](https://github.com/unjs/unenv). `unenv` is resolved from your project and installed on demand, only when the build imports such a module.

```ts
export default defineConfig({
  node: false, // target non-Node.js runtimes
});
```

### `replace`

Build-time string replacements.

```ts
export default defineConfig({
  replace: {
    "process.env.APP_VERSION": JSON.stringify("1.0.0"),
  },
});
```

### `commonJS`

Specifies additional configuration for the rollup CommonJS plugin.

```ts
export default defineConfig({
  commonJS: {
    requireReturnsDefault: "auto",
  },
});
```

### `exportConditions`

Custom export conditions for module resolution.

```ts
export default defineConfig({
  exportConditions: ["worker", "production"],
});
```

### `noExternals`

- Default: `false`{lang=ts}

Prevent packages from being externalized. Externalized packages are imported at runtime instead of being bundled, so they do not see your `alias` configuration.

In a production build Nitro already bundles almost everything: only native or otherwise non-bundleable packages and the ones listed in [`traceDeps`](#tracedeps) stay external. In development, dependencies inside `node_modules` are kept external for speed, which is where this option matters most.

Set it to `true` to bundle everything, including packages that are normally kept external:

```ts
export default defineConfig({
  noExternals: true, // bundle all dependencies
});
```

#### Inlining specific packages

Pass an array to inline only some modules. `RegExp` entries are used as-is; string entries are escaped and matched as a path substring.

Each pattern is tested against the import specifier as written (for example `@scope/my-lib`) and against the resolved absolute file path (for example `/…/node_modules/@scope/my-lib/dist/index.mjs`). A match on either one keeps the module bundled, so a plain package name is usually all you need:

```ts
export default defineConfig({
  alias: {
    "@shared": "./shared",
  },
  noExternals: ["@scope/my-lib"],
});
```

Use a path pattern when you need to be more precise, for example to inline one package in a monorepo without matching a similarly named one:

```ts
export default defineConfig({
  noExternals: [/packages[\\/]my-lib/],
});
```

Write `[\\/]` instead of `/` in such patterns so they also match Windows paths.

::note
In Nitro 2 this option was `externals.inline`.
::

### `traceDeps`

- Default: `[]`{lang=ts}

Additional dependencies to trace and include in the build output.

Supports special prefixes:
- `!pkg`: Exclude a built-in package from tracing.
- `pkg*`: Full trace, copies all package files instead of only traced ones.

```ts
export default defineConfig({
  traceDeps: [
    "sharp",
    "better-sqlite3",
    "my-pkg*", // full trace (copy all package files)
    "!unwanted-pkg", // exclude from tracing
  ],
});
```

### `traceOpts`

Advanced options passed to [nf3](https://github.com/unjs/nf3) for dependency tracing.

```ts
export default defineConfig({
  traceOpts: {
    // Options passed to @vercel/nft for file tracing
    nft: { /* ... */ },
    // Alias for module paths when tracing
    traceAlias: { "old-pkg": "new-pkg" },
    // Preserve or set file permissions when copying (true or octal like 0o755)
    chmod: true,
    // Transform traced files before copying
    transform: [
      { filter: (id) => id.endsWith(".js"), handler: (code) => code },
    ],
    // Hook into tracing lifecycle
    hooks: {
      tracedPackages(pkgs) {
        console.log("Traced packages:", Object.keys(pkgs));
      },
    },
  },
});
```

### `oxc`

OXC options for the `rollup` builder. Includes `minify` and `transform` sub-options.

`minify` uses the minifier of `rolldown`. If `rolldown` is not installed, minification is skipped with a warning.

```ts
export default defineConfig({
  oxc: {
    minify: { compress: true, mangle: true },
  },
});
```
