next-zonesv0.1.0

CLI

Command What it does
next-zones init <dir> [zone…] [--no-install] A new workspace: a shared package, the shell and its zones, installed (getting started)
next-zones add <zone> [--mount /<segment>] One more zone in the workspace of the current folder
next-zones check <dir> [more dirs…] Checks the zones' declarations: mounts, the shell, aliases (below)
next-zones doctor <dir> [more dirs…] [--store <dir>] [--url <zones url>] [--fast] Checks a workspace from source for everything Zones and dev need, with what to do (below)
next-zones build [--dir .] [--version <v>] [--store <dir>] [--pack] [--out <dir>] Builds the workspace as its shell declares (build and start): with mode: "zones", the shell as an app, every zone as an image, and zones.json pinning the versions built
next-zones build <zone>… [--dir .] [--version <v>] [--store <dir>] [--pack] [--out <dir>] Builds only these zones' images, to release what changed. The shell is not built
next-zones start [--dir .] [--store <dir>] [--source <url template | dir>]… [serve's options] Runs what build made: Zones, the shell, the pinned images
next-zones serve --shell <dir> [--store <dir>] [--cache <dir>] [--pins zones.json] [--policy zones.config.json] [--source <url template | dir>]… [--connector <origin> --connector-owner <owner>] [--keep 2] [--no-prune] [--min-free <MB>] [--port 3000] [--host 0.0.0.0] Runs the Zones, installing the pinned versions of zones.json (if present) under the store's state.json. --source (repeatable): where it pulls zone images from. --keep: the rollback window pruning keeps; --no-prune turns it off. --min-free: what a pull leaves free on the disk (1024 MB by default)
next-zones pack <zone image dir> [--out <file.tgz | file.zip>] Packs a zone image into one .tgz, the form a source serves (see zone images)
next-zones pull <zone> <version> --store <dir> (--source <url template | dir>… | --connector <origin> --connector-owner <owner>) [--min-free <MB>] Pulls a zone image into a store, on the server side (any zone): streamed, checked, then moved in. A deploy step
next-zones pull <zone> <version> --url <zones url> [--base /_next-zones] Pings a running Zones to pull it from its sources: only a zone that allows live pulls
next-zones prune --store <dir> [--keep 2] [--pins zones.json] [--cache <dir>] [--dry-run] Prunes a store no Zones runs on (refused while one does)
next-zones prune --url <zones url> [--base /_next-zones] [--keep 2] [--dry-run] Asks a running Zones to prune its store
next-zones install <zone> <version> [--url http://127.0.0.1:3000] [--base /_next-zones] Asks a running Zones service to install, swap to or roll back to a version
next-zones dev <zones dir> [--port 3000] Develops every zone at once: one next dev, with HMR and soft navigation (below)
next-zones watch <zones dir> <zone> [more zones…] [--url http://127.0.0.1:3000] [--base /_next-zones] [--store <dir>] Rebuilds zones on every change and installs them on a running Zones service (below)

start, serve, install, pull, prune and watch read the admin token from NEXT_ZONES_ADMIN_TOKEN. When the server has a token, a command must send the same one, even from the same machine: the loopback rule holds only with no token configured.

Build and start#

Like next build and next start, for a workspace of zones (run in the workspace's folder, or with --dir). The shell declares what the workspace builds to, with zoneConfig({ mount: "/", mode }):

Command Output Then
The workspace, mode: "zones" (default) next-zones build The shell built as an app (shell/.next); every other zone as an image in .zones-store/<zone>/<version>/, or packed into .zones-images/<zone>/<version>.tgz with --pack; zones.json pinning the versions built next-zones start
One zone, or a few next-zones build blog blog's image only (--pack: a .tgz). The shell is not built A running Zones installs it: next-zones install blog 1.4.0, or pulls it from where you published the .tgz
One app, mode: "single" next-zones build Every zone built once, as on Zones, then each zone's image linked into one standard Next app, following the shell's Next output (below). No zones.json, no Zones at run time next-zones start: next start of that app; see the outputs below

About build. It builds each zone where it is, as next build would (Turbopack's cache is reused from one version to the next). Two versions may give one id to different modules; Zones tells them apart by what each module is, its dependencies included: an open tab runs the new version's client code after a swap, and the server never hands one version another's module. The store defaults to NEXT_ZONES_STORE, else <zones dir>/.zones-store.

next-zones check#

next-zones check <dir> [more dirs…]

It reads every sub-folder of each <dir> whose next.config uses zoneConfig, and checks the set as a whole.

Check Error
Each mount is / or one segment blog: mount must be "/" or one URL segment like "/blog"
A mount has one owner / is claimed by 2 zones: a, b
Exactly one shell no zone owns "/": exactly one zone, the shell, must declare "mount": "/"
An alias does not land on a mount shop: alias /blog/:x lands on the mount of blog
Two zones do not share an alias segment aliases under /post are claimed by blog, shop

It exits with 0 when everything holds and 1 otherwise, so it can gate a build:

{ "scripts": { "zones:check": "next-zones check .", "build": "npm run zones:check && npm run build --workspaces" } }

With yarn 1, do not name the script check: yarn check is a built-in command.

next-zones doctor#

next-zones doctor . --store .zones-store --url http://127.0.0.1:3000
next-zones doctor . --fast            # without Next's and React's checks (lint, types)

It reads the workspace from source, before anything is built, and reports every finding with what to do. It exits with 1 on an error.

Check Why
The declarations, as check One shell, one owner per mount and alias segment
One next, react and react-dom for every zone Zones loads each once
basePath, i18n, trailingSlash, assetPrefix, skipTrailingSlashRedirect, cacheComponents, partialPrefetching equal to the shell's They shape every URL
No images key a zone sets of its own that differs from the shell's (a zone with none fits) The shell's image optimizer serves every zone
A zone's headers, redirects and rewrites under its mount or aliases Root rules belong to the shell
No proxy/middleware or instrumentation-client in a zone They would not run when the zone is reached from the shell
A zone's app/ holds its mount, plus root files used alone (layout, not-found, global-error, global-not-found, error, loading, template, default, CSS) Routes outside the mount are refused
No zone's mount or alias on a segment the shell's app/ serves (route groups included) A segment has one owner; refused at install
No edge runtime in a zone Not served by Zones yet
A zone's pages/ holds its mount (pages<mount>/, pages<mount>.tsx), plus _app, _document, _error, 404, 500 Pages outside the mount, pages/api/ among them (served at /api/…), are refused
A zone's public/ holds only public/<mount>/ Public files are served at the root, beside other zones'
env keys with one value across zones (warning) Composed by dev, a key has one value
A path alias that differs between zones has the form "prefix/*": ["folder/*"] The form dev gives each zone
.next/, node_modules/, .zones-dev/, .zones-store/, .zones-images/, .zones-cache/, .zones-app/, .zones-export/ ignored by git (errors); next-env.d.ts, *.tsbuildinfo (warnings) Asked of git itself (git check-ignore), so any .gitignore in the repository, or a global one, counts
Next's and React's checks (not with --fast): eslint-config-next's rules on each zone's sources, or the zone's own ESLint config; then next typegen and tsc --noEmit Neither Next nor React ships a doctor. These are their official checks: Next's plugin, React's hooks and compiler rules, and the type check next build runs. They run from the workspace's installs (eslint 9, eslint-config-next, typescript); nothing is downloaded
With --store: state.json pins versions in the store, built with the shell's Next and React Zones refuses them otherwise
With --url: a Zones answers at that URL (a warning when it does not)

next-zones dev#

next-zones dev . --port 3000          # then open http://localhost:3000

It composes the shell and every zone into one Next app, <zones dir>/.zones-dev/, and runs next dev on it:

What it writes. Nothing is copied: the app is made of links to the zones' own files, and Next sees every edit.

What zones must agree on, composed:

next-zones watch#

next-zones serve --shell shell --port 3000 &        # Zones, with the shell (its folder)
next-zones watch . blog shop                         # production builds, installed on every change

Zones runs production builds, so this is the way to try a change exactly as it will be served. It builds each zone once, then watches the zones dir:

A zone build takes 6–7 s for a small zone, and installing it about 200 ms.

Edit this page on GitHub · Markdown