# Build for production

Choose toolchain or native builds, configure PWA and budgets, and verify artifacts.

Requires WU CLI `1.2.0` and WU Framework `4.0.0` for application APIs. Check `wu --version` and the project dependencies.

<span id="dos-caminos-de-construcción"></span>

<span class="section-anchor" id="section-1"></span>

## Two build paths

```sh
wu build
wu build --native
wu serve 4100
```

`wu build` keeps the toolchain path: it builds shell and apps through their commands, assembles `dist/`, writes manifests and generates HTTP policies. `wu build --native` starts the WU server in production mode, crawls the module graph and publishes its responses as static files. Choose one path per build; verify either output in a browser.

| Option | Effect |
| --- | --- |
| `--native` | Builds from WU server responses. |
| `--no-pwa` | Disables PWA for this native build. |
| `--budget-warn` | Makes budget overruns warnings. |
| `--jobs <n>`, `-j <n>` | Between 1 and 64 concurrent builds; default `min(CPU, 4)`. |
| `--no-cache` | Does not reuse outputs from `.wu-cache/builds/`. |
| `--sign <key.pem>` | Signs `dist/wu-integrity.json` with ECDSA P-256. |

There are no `--watch`, `--app`, `--out-dir` or `--minify` flags. A compile failure, an app with no output, an unwritable file or an exceeded budget returns `1`. The build works in `dist.tmp-<id>/` and replaces `dist/` only on success; a failure preserves the previous build and leaves evidence in `dist.failed/`. A second concurrent build is rejected through `.wu-cache/build.lock`.

<span id="caché-de-compilación-y-builds-anteriores"></span>

<span class="section-anchor" id="section-2"></span>

## Build cache and previous builds

Unchanged apps restore their output from `.wu-cache/builds/`. The key includes local sources, `.env*`, root manifest, lockfiles, overrides, command, framework, shared modules and CLI version. Imports outside the app directory and edits in `node_modules` are not detected: use `--no-cache`. On Windows, process environment variables are also excluded; avoid reusing cache after changing them.

`build.keepPreviousBuilds` retains hashed files from two previous builds by default; `0` keeps only the current one. The private record `dist/.wu-builds.json` lets older tabs keep loading their chunks. In clean CI, preserve `dist/` between builds or use a host that retains those files. HTML, manifests and the service worker belong only to the current build.

```json
{ "build": { "keepPreviousBuilds": 2 } }
```

<span id="un-runtime-compartido"></span>

<span class="section-anchor" id="section-3"></span>

## One shared runtime

The CLI detects `wu-framework` and browser subpath imports, shares core and creates the conventional build import map. To externalize those imports, `build_cmd` must expose a direct `vite build` invocation. An opaque command such as `npm run build` can prevent WU from inserting externals and aliases; check warnings and module requests.

`wu create` prepares `shared` for generated frameworks and `wu add` extends it. Sharing React or Preact includes the JSX runtime emitted by the compiler. Explicitly import the [optional subsystems](/docs/framework/runtime-composition/) the shell uses. If a local toolchain is missing, run `wu install`; do not assume the CLI substitutes a root version.

Import maps are inserted or merged into every HTML page, after `<head>`; fragments and files larger than 8 MiB are skipped. Sharing a Qwik or Svelte adapter also shares its runtime. WU-generated entries include SRI on scripts and modulepreloads, and `integrity` in the import map. Generated helper scripts are external.

<span id="qué-publica-el-build-nativo"></span>

<span class="section-anchor" id="section-4"></span>

## What the native build publishes

The native build crawls every shell page and app entry. It publishes modules, CSS and assets with SHA-256-derived names, replacing the old `?v=<build>`. Unchanged content keeps its URL and module identity. Compile errors stop the build instead of publishing the overlay module.

Dynamic imports with computed URLs cannot be discovered by following literal imports. `.module.css` still retains development-server style injection. Verify these cases before choosing native builds; retain toolchain builds when your application needs different processing.

<span id="pwa-caché-y-actualizaciones"></span>

<span class="section-anchor" id="section-5"></span>

## PWA, cache and updates

Native builds generate `wu-sw.js`, `wu-sw-register.js`, `manifest.webmanifest` and an icon when PWA is enabled. They precache discovered files; navigation and catalog requests try the network first and fall back offline. External API data and files outside the discovered graph are not automatically precached.

`pwa: false` at the root of `wu.config.json` or `--no-pwa` disables generation. An existing shell manifest is preserved. The worker serves installed apps under `/@wuapp/` from the `wu-apps` cache and keeps that cache when updating a build. Listen for `wu:update-available` and `wu:sw` if the shell needs update status.

The new worker waits while other windows are open. The `wu:update-available` event exposes `event.detail.activate()` so the shell can decide when to activate the replacement. Offline navigations retrieve their own page; same-origin APIs do not automatically enter the site cache.

<span id="presupuestos-por-app"></span>

<span class="section-anchor" id="section-6"></span>

## Per-app budgets

```json
{ "budget": "150kb", "apps": [
  { "name": "cart", "dir": "mf-cart", "framework": "react", "port": 5001, "budget": "80kb" }
] }
```

The app budget overrides the root budget. Use numeric bytes or units such as `80kb` and `1.5mb`, with base 1024. Counts include uncompressed `.js`, `.mjs` and `.css`; images and fonts are excluded. Exceeding it returns `1` and preserves the previous `dist/`. `--budget-warn` retains the warning without failing the build. This is a project limit, not a performance comparison with other frameworks.

<span id="revisar-el-resultado"></span>

<span class="section-anchor" id="section-7"></span>

## Verify the output

Check `dist/wu-manifest.json`, app entries, `_headers`, `vercel.json` and `wu-security.conf`. Serve `dist/`, reload nested routes, mount every app, and check CSS, communication and console output. Also test an offline reload when using PWA. To distribute one app, continue with [wu pack](/docs/cli/pack/).

<span id="publicar-y-verificar-un-build-firmado"></span>

<span class="section-anchor" id="section-8"></span>

## Publish and verify a signed build

```sh
wu pack --keygen keys/deploy.pem
wu build --sign keys/deploy.pem
wu doctor --url https://example.com --integrity --pubkey keys/deploy.pub.json --json
```

Save the public JWK printed by `--keygen` in `keys/deploy.pub.json`. Publish all of `dist/`, including `wu-integrity.json`, with the policy files from the same build. The signed manifest records hashes, types, import maps and per-page CSP. `doctor --integrity` verifies the signature and responses; without `--pubkey`, it checks only the key carried by the manifest, not a trusted identity.

The CDN must preserve bytes, MIME, CSP and import maps: an automatic transform after signing invalidates verification. Use immutable caching only for hashed files and revalidate HTML, manifests and the worker. Do not delete earlier chunks during the retention window. WU generates per-page policies for `_headers`, `vercel.json` and `wu-security.conf`, preserves the shell’s `_headers` and warns about Cloudflare rule and line-length limits.

<span id="referencia-de-implementación"></span>

<span class="section-anchor" id="section-9"></span>

## Implementation references

- `wu-cli/src/commands/build.zig`
- `wu-cli/src/commands/build-native.cjs`
- `wu-cli/src/commands/deploy.zig`
- `wu-cli/src/commands/build_cache.zig`
- `wu-cli/tests/build-deploy.test.cjs`
- `wu-cli/tests/build-native-pages.test.cjs`
- `wu-cli/tests/build-failures.test.cjs`
- `wu-cli/tests/build-shares-adapter-runtime.test.cjs`