Rule 1: The page step must come first
Include steps that appear before the page step are invisible to the pipeline — their tokens remain as literal text in the output. Always put the page step first.
How SSI processes steps in sequence
SSI is a sequential pipeline. Each step scans the full accumulated page text for its tokens and replaces them. The source of a token — whether it arrived from a previous include step, was expanded from a block file, or was written directly in the page template — makes no difference to later steps. All that matters is whether the token is present in the text when the step runs.
Include steps that appear before the page step are invisible to the pipeline — their tokens remain as literal text in the output. Always put the page step first.
If a block file contains a 💬 token, the HTML include step for that block must run before the plain-text include step that resolves 💬 tokens. The plain-text step scans whatever text is present when it runs — so the blocks must already be expanded.
Adding options = ["leftovers-okay"] to an include step excludes it from SSI's include validation. SSI will not warn about tokens from this step with no matching source files, and will not warn about source files that no page references. Use it for supplemental documentation content, optional code examples, or any include source where incomplete coverage is acceptable.
Once a step places content into the accumulated page text, later steps cannot tell where it came from. A 💬 token that arrived from an HTML include, a Markdown include, a TOML value, or was typed directly into the page template is treated identically by the next step.
The feature section you are reading right now was assembled across two include steps. The HTML include step expanded the 📦 token in the page template, placing the block's structure — including a 💬 token for this title — into the page text. The plain-text include step then resolved that 💬 token along with all the others.
The code below is included by the last include step, which runs
with options = ["leftovers-okay"] because the code
comments contain token-like patterns as display text, not active
tokens.
# Correct step order for this example:
#
# 1. Page step — always first.
[[step]]
emoji = "📄"
path = "pages/"
processing = "page"
# 2. Copy step — static assets; position does not affect token resolution.
[[step]]
emoji = "🎨"
path = "assets/"
processing = "copy"
# 3. HTML include step — runs before the plain-text step because block files
# may contain 💬 tokens that the plain-text step needs to resolve.
[[step]]
emoji = "📦"
path = "blocks/"
processing = "include"
type = "html"
# 4. Plain-text include step — resolves 💬 tokens from pages AND from
# block files expanded in step 3. Must run AFTER the HTML include step.
[[step]]
emoji = "💬"
path = "strings.toml"
processing = "include"
type = "plain"
options = ["inline"]
# 5. Code-display include step — runs last with leftovers-okay.
# leftovers-okay excludes this step from include validation: SSI will not
# warn if pages reference a 📁 token with no matching file, and will not
# warn about files in code-examples/ that no page references. Use it for
# documentation content where incomplete coverage is acceptable.
[[step]]
emoji = "📁"
path = "code-examples/"
processing = "include"
type = "html"
options = ["leftovers-okay"]