Skip to main content
Frontmatter is the block between two --- lines at the top of a .slurp file. The delimiters must be at column 1. Every directive is optional, and so is the block.

The complete list

Directives may appear in any order, and repeated using, type and props statements accumulate. A second section { } or a second block { } is an InvalidFrontmatter error; both may appear in the same file.
Unknown statements are silently skipped. A misspelled directive produces no diagnostic at all.
Both lines are accepted and ignored. There is no layout directive; use the {layout "..."} block tag in the body. InvalidFrontmatter fires only on a MALFORMED known directive, never on an unrecognised one.

using

The local name is the alias if one is given, otherwise the last path segment. So using "@components/Card" introduces Card, which is what makes <Card /> resolve. @-prefixed paths are registry keys the host resolves. The CLI resolves @components/X and @layouts/X against the project directory.
An unresolvable import is not an error. The component renders a placeholder:
A typo in an import path therefore looks like a clean build with a missing card. Grep the output for data-slurp-component when something is unexpectedly absent.

using type

Imports type names for editor tooling. It introduces no component and has no effect on rendering. The from keyword is required; omitting it is InvalidFrontmatter.

type

Declares a shape for use in props or a {fetch} type hint. A ? marks a field optional. Type expressions are stored as raw strings and are never checked, at parse time or at render time. TypeMismatch is declared in the error enum and never emitted. The names are for humans and for editor tooling.

props

required
The prop name. A ? immediately after it marks the prop optional.
required
A type expression, stored as a raw string. Append [] for an array.
Optional. The expression is evaluated in the caller’s scope when the prop is not passed.
Prop types and requiredness are recorded and NEVER validated at render time, so a missing required prop is simply null. MissingRequiredProp and UnknownProp are both declared and never emitted; passing a prop the component never declared is not an error either.
A type expression runs to the end of the line. It terminates at a newline, a comma, a =, or the closing brace. So several space-separated declarations on one line collapse into a single prop whose type expression swallows the rest:
Adding a = default also terminates the type expression, so the one-line form happens to work once every prop has a default. Because types are never enforced, the collapse is otherwise invisible at render time. Write one prop per line anyway: the collapsed form is what the editor tooling reads back.

Defaults are evaluated in the caller’s scope

components/Card.slurp
Rendered from a page whose context has count5 = 5, <Card /> produces <div>5</div>. The default expression is resolved where the component was written into the page, not inside the component.

middleware

Both the quoted and the bare form are accepted, and both only RECORD a name.
Middleware is a compile option, not a filename or frontmatter convention. What makes a file middleware is CompileOptions.is_middleware, supplied by whoever invokes the compiler. On the CLI that is the --middleware <DIR> flag.Without it, every file is treated as non-middleware, so a correct middleware file reports MiddlewareScopeViolation for its request.* reads, and a broken one is never checked at all.
Inside a file compiled as middleware, the scope rules invert: request.*, {redirect} and {next} become legal, and the only path roots allowed are request, env and loop. Reading any other root there is MiddlewareScopeViolation.

section { } and block { }

These declare a typed editor surface. The grammar is large enough to have its own page: see Schemas. section, settings, blocks, name, max and max_per_page are CONTEXTUAL keywords. They lex as ordinary identifiers and gain meaning only at that exact structural position, so a template using any of them as a prop name or a type name is unaffected. A section statement is recognised only when a { follows it immediately.

env and secrets

env.* is readable from a template, with one hard restriction enforced at compile time:
The gate covers three cases, all under the same code: A non-constant key is refused because it could resolve to a secret name. Read the secret on the server and pass only a derived, non-secret value through the render context.