Configuration
A Zigapagos project is configured in two places: zigapagos.ziggy describes the site, and the zigapagos release invocation that builds it declares the islands and SPAs to compile.
zigapagos.ziggy
Site {
.title = "My Site",
.host_url = "https://example.com",
.url_path_prefix = "",
.content_dir_path = "content",
.layouts_dir_path = "layouts",
.assets_dir_path = "assets",
.deploy_target = "zigbase",
.sitemap = true,
}
.title is available in every layout as $site.title.
.host_url is the origin used to build absolute URLs — canonical links, feeds, and social metadata.
.url_path_prefix is the subpath the site is served from. On GitHub project pages this is the repository name. Set it and then never hand-write an internal URL: $site.page('docs/overview').link() and $site.asset('style.css').link() apply the prefix, and a literal /docs/ does not, so a hardcoded link works locally and 404s in production.
.content_dir_path, .layouts_dir_path and .assets_dir_path are relative to the project root.
.deploy_target selects which host configuration the build emits — zigbase, nginx, or apache. See native SPAs for what each one generates.
.image_optimize = {} turns on build-time image optimization: WebP variants of every content image at configured widths, emitted as a <picture> with a full srcset/sizes and the untouched original as the fallback, with opt-in AVIF via an external encoder you supply. Off by default (null). Images is the full reference, including the variant cache and the failure rules.
.speculation_rules = true injects a browser-native <script type="speculationrules"> prefetch hint into every rendered page: supporting browsers prefetch same-origin links on hover, with zero runtime JS, and browsers without support ignore the block. Off by default; the islands reference covers it under link prefetching.
.sitemap = true emits sitemap.xml at the output root: one entry per canonical page URL, composed from host_url + url_path_prefix exactly like every other absolute link this build writes. Drafts and alias/alternative duplicates are excluded; a paginated section’s page-2+ windows are included; a prerendered SPA route is included only when it is a real, indexable page — a static route or a staticPaths concrete entry (never a dynamic route’s own pattern shell, since nobody can visit /app/club/:id as a URL), and never a route belonging to an SPA whose noindex is on (the default) — a sitemap listing a URL the same build tells crawlers not to index is a Search Console error, not a feature. Off by default. Requires host_url to be set — which every zigapagos.ziggy already must, so there is nothing extra to configure. A page whose aliases or alternatives output resolves to the site-root sitemap.xml is a build error while the sitemap is enabled, since either would otherwise silently collide with it.
sitemap is a Site-only field — a multilingual zigapagos.ziggy (Multilingual { ... }) has no field of this name, so setting it there is a config-parse-time “unknown field” error, not a silent no-op. Composing one crawler-facing URL set across per-locale hosts/prefixes is a bigger design than this feature covers yet.
zigapagos dev‘s incremental rebuilds (the fast path that re-renders only changed content pages) never touch sitemap.xml: only a full, non-incremental build (the dev loop’s first build, or a plain zigapagos release) writes it, so a previously-written sitemap is left as-is — stale, not wrong-shaped — until the next full rebuild.
The build invocation
zigapagos is a standalone executable, so a project’s build is one command rather than a build graph — nothing here needs a Zig toolchain. Keep that command in a build.sh at the project root so the entries are declared in exactly one place; zigapagos init --from-astro scaffolds one for you.
#!/usr/bin/env bash
set -euo pipefail
cd ""
exec zigapagos release \
--force \
--output=public \
--island=components/Counter.island.tsx \
--spa='app/app.spa.tsx|/app' \
--spa-not-found=app \
"$@"
--island=SRC names one island source as a path relative to the project root, and that path is what an <island src="…"> attribute must match. Repeat the flag once per island.
--spa=SRC|BASE registers a native SPA. BASE must equal the base exported from the .spa.tsx module. The build validates the match and fails loudly if they diverge, because a mismatch produces an application whose router and whose prerendered shells disagree about where they live.
--spa-not-found=NAME names which SPA owns the site-wide 404.html, by file basename without the .spa.tsx suffix. Set it explicitly when there is more than one SPA; otherwise declaration order decides, which is not a property you want a deployment to depend on.
--output=DIR is the output tree (default public/), and --force lets the build overwrite one it did not create. Run zigapagos release --help for the rest.
A note on failure and partial output
Build failures write the output tree in place, so a failure partway through leaves a partially updated site. The pass order limits the damage — SPA validation runs before any page is written — but it is not atomicity. Build to a staging directory if you are deploying by syncing the output tree.