Skip to main content
A page is a .slurp file that Slurp writes an HTML file for. There is no route table and no config: the input tree is the route tree, and the output tree mirrors it.

One file in, one file out

Each page keeps its path and swaps its extension.
Nested directories are created as needed. Nothing is renamed, flattened or given a trailing slash, so the source tree and the output tree have the same shape.

Which files are pages

Everything, except two directories: This is a blocklist, not an allowlist of pages/. A lone index.slurp in an otherwise empty directory is a valid one-page site, which is what the Quickstart builds.
The match is on the FIRST path segment and on the exact name. So components-archive/Old.slurp becomes dist/components-archive/Old.html, and src/components/Card.slurp becomes dist/src/components/Card.html. Neither is excluded, and the build emits HTML files for fragments that are not documents. Keep both directories at the input root and spell them exactly.
Components and layouts are still compiled. A syntax error, an unknown filter or a security violation in a component that no page happens to import yet is caught now rather than later. --verbose shows the distinction:

Everything else is copied through

Any non-.slurp file in the input tree is copied to the output verbatim. Stylesheets, images, fonts and robots.txt need no configuration.
The --globals file is the one exception. It is build input, not a site asset, and publishing it would expose its contents at a guessable URL, so it is skipped. The output directory is skipped too, so rebuilding into a directory inside the input tree does not copy the last build into the next one.

The pages/ convention

Slurp does not require a pages/ directory, but hosts that serve a Slurp theme generally resolve a request for /about to pages/about.html, and the bundled dev server does the same. For a theme written against a host rather than a standalone static site, put pages under pages/. The layout the example theme uses:
A build that emits nothing reports it:

Dynamic routes

A filename in brackets is an ordinary page as far as the compiler is concerned: pages/[slug].slurp compiles to pages/[slug].html, brackets and all. The brackets mean something to whatever serves the file, not to slurp build.
pages/[slug].slurp
The dev server matches an extensionless URL segment against a bracket file in that directory and binds the segment as a top-level value under the bracket’s name, so /premium-wallet renders the file above with slug set to premium-wallet.
The value lands at the top level, not under params. params has no special meaning to the compiler at all: it is an ordinary context key that hosts conventionally populate, and ${ params.slug } reads it only if the host populated it.

The 404 page

There is no special handling for 404.slurp. It is a page like any other and compiles to 404.html; serving it on a miss is your host’s job. The dev server does not, and returns a plain-text 404 instead. Write it anyway. It ships with the theme, and a host that wants a themed error page has one to point at.

Page data

A page renders against a JSON context. Every top-level key in that context is a global the page can read.
data.json
index.slurp
--globals is ONE context for the whole build. Every page in the run sees the same keys, so there is no per-page data file. Pages differ by reading different keys out of a shared context.
This is a limit of the static path: --globals is build-time data, not page data. When Slurp is embedded in a server the context arrives per request from the host, and each page gets its own. See Embedding with Rust.

Declaring a data dependency

{fetch} declares a data dependency. At build time no request is made: the renderer looks up the fetch name in the context and picks a branch.
With products present in the context, that renders the body. With the key absent or null, it renders {loading}. The from URL is recorded for a host or the dev server to act on, never fetched by slurp build.

When a build fails

Errors are reported per file and the build keeps going. A page with a syntax error is skipped and no HTML is written for it; every other page is still written. Only at the end does the process exit non-zero.
So a failed build leaves a partial site on disk, with the broken page missing rather than stale. Check the exit code, do not check whether dist/ looks populated.
validate compiles the same files and emits nothing, which suits CI.
Add --verbose to build and --warnings to validate while you work. Slurp fails quietly, and those flags turn silent truncations and unresolved values into printed lines.

Next

Components

Props, scope, slots, and imports.

Layouts and slots

Layouts, slots, and the head block.

Project structure

Special directories, output paths, and static assets.

CLI

Every flag on build, validate and dev.