Skip to content

Guide 34 of 36

Verniz runtime and deploy

Build sealed static, hybrid and server products with reproducible runtime artifacts, content-addressed caching and provider-neutral deployment.

On this page

Verniz can publish one sealed directory containing prerendered pages, browser assets, an optional standalone Zolo server, install/offline metadata, and a provider-neutral static edge adapter. The page does not import a hosting provider SDK: every runtime consumes the same Deploy Manifest v2. The standalone loader remains backward-compatible with Deploy Manifest v1/WebManifest v15 artifacts.

Choose the product and backend

[project]
entry = "src/main.zolo"

[web]
output = "hybrid" # static | hybrid | server
out_dir = "dist"
base = "/"
trailing_slash = "always"

[web.runtime]
backend = "llvm" # llvm | native
profile = "release" # release | debug

llvm + release is the production default. native selects Cranelift and is useful when build latency matters more than the last production optimization. The command line can override the project without editing it:

zolo build --web=hybrid --runtime-backend=llvm --release
zolo build --web=hybrid --runtime-backend=native --debug

A purely static product never compiles or ships a server. Hybrid/server products compile the same entry program selected by the WebGraph.

Published layout

dist/
├── index.html
├── 404.html
├── _zolo/
│   ├── web-manifest.json
│   ├── deploy-manifest.json
│   ├── edge/              # opt-in
│   │   ├── adapter.wasm
│   │   ├── adapter.json
│   │   └── host.mjs
│   └── runtime/
│       └── server.exe       # `server` on Linux/macOS
├── manifest.webmanifest     # opt-in
├── sw.js                    # only with [web.pwa.offline]
└── ... browser assets

WebManifest v16 and Deploy Manifest v2 agree on runtime, PWA/offline, edge, routes, capabilities, files, byte lengths, and BLAKE3 digests. The standalone adapter rejects a changed manifest, binary, page, asset, route/action graph, capability set, path escape, or symlink before it opens the port. Stable PWA/edge filenames are served with no-cache; content-addressed browser chunks remain immutable.

The server binary is not a browser asset and does not count against JavaScript or route payload budgets. Its size and identity are printed separately in the build report.

Preview the complete product

zolo preview dist

For static, preview serves only the sealed files. For hybrid or server, it validates and starts _zolo/runtime/server[.exe]; prerendered routes and immutable assets win before runtime route matching. Closing preview also closes the child server, including on Windows.

The generated executable discovers _zolo/deploy-manifest.json beside itself, so the directory can be copied as a unit and launched directly:

$env:PORT = "8080"
dist\_zolo\runtime\server.exe

ZOLO_HTTP_PORT has priority over the conventional PORT. Supervisors may set ZOLO_DEPLOY_MANIFEST to an explicit manifest path; this is also how the VM parity tests consume the exact deployed product.

The transport removes [web].base before calling the authored router. For example, with base = "/docs/", public /docs/account/42 reaches the application as /account/42. Canonical slash redirects, HEAD, the sealed 404, actions, form bodies, and local 303 redirects keep the same behavior on VM, LLVM, and Cranelift.

Runtime cache

Compiled servers are cached under target/.zolo/web-runtime/<key>/. The key includes compiler identity, WebGraph program hash, backend, profile, target, plugins, and the exact runtime static library hash. A valid second build reports cache hit and reuses the executable; corrupted metadata or bytes are never reused.

Changing a static page without changing the runtime program can therefore keep the expensive AOT artifact. Changing the program, backend/profile, target, compiler, plugin set, or runtime library selects a different cache entry.

PWA and auditable offline behavior

[web.pwa]
short_name = "My site"
start_url = "/"
display = "standalone"
theme_color = "#111827"
background_color = "#ffffff"

[[web.pwa.icons]]
src = "/icons/app.svg"
sizes = "any"
type = "image/svg+xml"
purpose = "any maskable"

[web.pwa.offline]
routes = ["/", "/offline/"]
fallback = "/offline/"
max_bytes = "1 MiB"

[web.pwa] alone emits only manifest.webmanifest: no registration script and no service worker. [web.pwa.offline] is the separate caching opt-in. It requires at least one static route and a positive byte budget. Verniz precaches only those documents and their transitive sealed Asset Graph dependencies; runtime routes are never eligible.

Documents use network-first. Cached HTML is considered only when fetch rejects, never for a 4xx/5xx response. A query-bearing navigation cannot reuse a cached page path; only the explicitly authored generic fallback may answer an actual network failure. The service worker never performs runtime cache.put, so its complete population, cost, hash, provenance, and reason are visible before deploy in WebManifest, the build report, and zolo explain web.

Removing [web.pwa.offline] removes sw.js and registration while preserving zero-JS install metadata. Removing [web.pwa] removes the capability completely on the next atomic build.

Adapters

Two provider-neutral adapters are available now:

  • static-dir: deploy the validated directory to any file host when output = "static".
  • standalone: run the declared server artifact and serve its sealed static/runtime product when output = "hybrid" | "server".
  • edge-wasm: opt-in import-free WebAssembly data module plus a small Fetch API host and deterministic descriptor for the complete static response graph.

Enable the edge product explicitly and bound its module size:

[web.edge]
runtime = "reject" # reject | origin
max_module = "2 MiB"

reject refuses a product containing runtime routes. origin records their exact method/pattern graph as an origin boundary, but does not invent an origin URL, environment binding, or provider SDK; the deploy host must pass an explicit origin callback to createEdgeHandler. The module embeds only already-finalized static response bytes, exports memory, imports nothing, and identifies its ABI through zolo.edge-abi. The descriptor records offsets, status, MIME, cache policy, redirect/404 behavior, hashes, source reason, embedded-byte cost, and runtime boundary. Build and preview regenerate and validate it byte-for-byte.

Provider adapters should translate Deploy Manifest v2 into host configuration. Pages and components must never import Cloudflare, Netlify, Vercel, or another deployment SDK to select their runtime behavior. Removing [web.edge] removes all three edge artifacts without changing the static/standalone product.

The complete executable example is examples/features/36-web/24-hybrid-product.

The complete PWA/offline/edge example is examples/features/36-web/27-pwa-edge.

Next: Verniz navigation.

DOCS / FEEDBACK

Did this page leave a question?

Tell us where the explanation lost you. Documentation is part of the language experience.

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

en