# 18.x → 19.0.0, entry by entry

**Both entries cost an edit only if you had `pwa.enabled: true`** — the same block 18.0.0 grew, for
the same reason one release later: 18.0.0 wired the web manifest and left the service worker with
zero callers, so `pwa.offline` steered nothing and `/offline` was a path no build precached.
`x dev`, the container and `x build --target static` all emit `sw.js` and `x-sw-register.js` now,
and the config had to be able to say what they emit.

| # | Surface | Costs you an edit if |
|---|---|---|
| 1 | `AppConfig.pwa.offline` | you set `pwa.enabled: true`. It was `'precache' \| 'runtime' \| 'network-only'` — an app-wide **default** for a field `defineRoute` makes **required** on every route, so it defaulted nothing and was read by nobody. It is now `{ fallback, image, font, neverCache }`, and **`fallback` is required** once `enabled` is true: an absolute route path, screened at `defineConfig` rather than at `x build`. The edit is one line — `offline: 'runtime'` → `offline: { fallback: '/offline' }` — plus a route at that path. A relative value is refused because it resolves against whatever document registered the worker, so `offline` served under `/posts/1` is `/posts/offline`: a 404 cached as the answer to every offline navigation. **Or set `pwa.enabled: false`.** Per-route `offline:` is unchanged, and is still where the strategy is declared |
| 2 | `x new`'s scaffold | you regenerate an app, or you copied the old scaffold. The offline fallback is `apps/web/site/offline/page.tsx`, not `apps/web/app/offline.tsx`: the directory is the URL and `<name>.tsx` is not a route file, so the old path shipped a component nothing imported and left `/offline` a URL that did not exist. `site/` and `render: 'static'` deliberately — the document that answers a lost network must render with no network, no session and no database, which `app/` (`ssr \| stream`) cannot promise. An existing app moves the file and adds `offline: 'precache'`, `hydrate: 'never'` and `robots: { index: false }` to its `defineRoute` |

**`x build --json` renames one field**: `precacheWarnings` → `serviceWorkerWarnings`, and the
terminal row is labelled `service-worker`. It is listed here rather than as a third entry because
no released build ever wrote the old key — `PrecacheManifest.warnings` had no reader at all until
this release. The list carries the precache byte ceiling **and** `pwa.push: true` with no VAPID key
to sign a subscription with, which is the one PWA capability still unwired.
