Boltdocs 3.1.0 — Turbo Mode, Sätteri MDX, and Zig Critical CSS

Jesús AlcaláJesús Alcalá
Boltdocs 3.1.0 — Turbo Mode, Sätteri MDX, and Zig Critical CSS

3.1.0 ships the --turbo flag: a Rust-based MDX compiler, Zig-compiled critical CSS extraction, and a single-pass parser. Phase 1 of the road to 4x faster builds.

This one's about the foundationLink

3.0.0 was about raw speed — the native parser. 3.1.0 is about the next layer: turbo mode. This is Phase 1 of Project Nitro, and it changes what runs under the hood when you build.

Info
Note

An experimental --turbo flag that swaps the MDX compiler for Rust-powered Sätteri, replaces Beasties with Zig-compiled critical CSS extraction, and enables a single-pass parser mode. This is the first step toward 4x faster builds.

Info
Note

Build output optimized: Beasties critical CSS inlining has been disabled by default, reducing total HTML output by ~7.3 MB. The default locale duplication bug has also been fixed, saving an additional ~8 MB. Combined, the build output is now ~60% smaller.


--turbo — Experimental Build ModeLink

The new --turbo flag activates three native-powered optimizations in a single command:

pnpm boltdocs build --turbo

Or set it permanently via environment variable:

BOLTDOCS_TURBO=true pnpm boltdocs build

What changes under the hood:

ComponentWithout --turboWith --turbo
MDX compilation@mdx-js/rollup + remark/rehype JS pluginsSätteri (Rust) + native plugins
Critical CSSNone (external CSS only)@bdocs/zig-critters (Zig/WASM)
ParserMulti-pass modeSingle-pass with shared buffer
Info
Note

This flag is experimental. You may encounter CSS compatibility issues from zig-critters or MDX compilation differences from Sätteri. If something breaks, remove --turbo and report the issue — your standard build is unaffected.


Sätteri MDX — Rust-Powered CompilationLink

The biggest change in --turbo mode is the MDX compiler. Sätteri replaces @mdx-js/rollup with a Rust-based processor built on pulldown-cmark with MDX extensions.

The pipeline:

  1. Rust parser (satteri-pulldown-cmark) parses Markdown/MDX into an arena-allocated AST
  2. MDAST plugins run on the arena (remark-meta, remark-gfm)
  3. AST converts to HAST
  4. HAST plugins run (rehype-slug, rehype-shiki)
  5. mdxToJs() compiles HAST to JSX output

Benchmarks from the Boltdocs docs site (241 pages):

MetricDefault (@mdx-js/rollup)Turbo (Sätteri)Difference
Build Time97.3s43.9s2.2x faster
SSG Total98.7s45.1s54% faster
JavaScript Output10.5 MB8.4 MB20% smaller
HTML Output25.65 MB15.51 MB40% smaller

Sätteri also includes three native sub-plugins that replace the standard remark/rehype equivalents:

  • satteriRemarkMetaPlugin — captures code fence meta strings into hProperties.metastring
  • satteriRehypeSlugPlugin — adds id attributes to headings
  • satteriRehypeShikiPlugin — Shiki syntax highlighting via HAST visitor

Fallback behaviorLink

If Sätteri fails to compile a file, it automatically falls back to @mdx-js/rollup with basic plugins (remark-gfm, remark-frontmatter, rehype-slug). Your build won't break — it just won't be turbo for that file.

Known limitation: legacy plugin compatibilityLink

Sätteri uses a Rust arena for HAST nodes. Standard unified/remark/rehype plugins that mutate nodes in place won't work — Sätteri requires a return-to-replace pattern. If you use custom plugins via remarkPlugins or rehypePlugins in your config, they may not apply in turbo mode. The adapter layer detects this and logs a warning.

For now, turbo mode is best for sites with standard MDX (code blocks, GFM tables, frontmatter). Custom plugin-heavy sites should stick with the default compiler.


@bdocs/zig-critters — Zig-Compiled Critical CSSLink

Beasties extracts critical CSS by loading your HTML and CSS, matching selectors, and inlining only the rules that apply above the fold. It works — but it's written in JavaScript.

@bdocs/zig-critters is a complete rewrite in Zig, compiled to WebAssembly. Same algorithm, native speed.

How it works:

  1. Loads the pre-compiled WASM binary on first use
  2. Encodes your HTML and CSS into WASM linear memory
  3. Parses CSS into rules, parses HTML into a flat element list
  4. Matches selectors against elements, marks unused rules
  5. Serializes only the critical rules back to JS

The result is injected as a <style data-zig-critters>...</style> tag before </head>.

What it supportsLink

  • @media and @supports containers — kept if any child rule matches
  • @keyframes — three strategies: critical (only used), all, none
  • @font-face — optional inline via inline_fonts
  • @property rules — always kept
  • Comment-based include/exclude directives
  • CSS minification (enabled by default)

Known limitation: CSS compatibilityLink

zig-critters strips pseudo-classes and pseudo-elements when matching (matching Beasties behavior). This means :hover, :focus, and viewport-dependent selectors are matched against their base element only. Some edge cases with complex selector chains may produce different critical CSS output than Beasties.

If you notice styling issues in turbo mode, try removing --turbo to confirm it's a zig-critters issue, then report it with a reproduction.


Single-Pass Parser ModeLink

The native Zig parser already runs 5-6x faster than the old JS parser. In turbo mode, it switches to a single-pass algorithm:

  • Normal mode: parseDoc() — two passes (one for frontmatter/headings, one for plain text)
  • Turbo mode: parseDocSinglePass() — one pass with a shared ParseContext buffer

Same output, less memory allocation. The single-pass mode generates headings, plain text, and content in one scan with arena-style allocation.


Feature Flags & DraftsLink

Control which pages are visible in each environment without code changes or conditional builds.

DraftsLink

Mark any page as a draft in frontmatter:

---
title: Upcoming Feature
draft: true
---

Draft pages are automatically excluded from production builds. In development, drafts are visible by default. Control visibility via config:

export default defineConfig({
  drafts: {
    visible: false,              // Hide in all environments
    environments: ['development', 'staging'],  // Or per-environment
  },
})

Or use the BOLTDOCS_DRAFTS=true environment variable to force visibility.

Feature FlagsLink

Define feature flags in your config:

export default defineConfig({
  featureFlags: {
    'new-dashboard': true,           // Always visible
    'beta-api': 'development',       // Only in development
    'experimental-search': false,    // Always hidden
  },
})

Then mark pages with required flags:

---
title: New Dashboard
featureFlags:
  - new-dashboard
  - beta-api
---

The page only renders when all declared flags are active. Perfect for progressive rollouts, A/B testing, or hiding internal tools from production.

Info
Coming Soon

Feature flags will integrate with the Ask AI plugin in v3.2.0 to enable context-aware responses based on enabled features.


Build Output OptimizationsLink

Beasties Disabled — Why?Link

Beasties was previously enabled by default, extracting "critical" CSS and inlining it into every HTML page as <style> tags. The problem: Beasties has no viewport awareness — it doesn't use a headless browser. It simply matches CSS selectors against the DOM and classifies any rule that matches any element as "critical."

With Tailwind CSS, nearly every utility class is used somewhere on the page. This means Beasties inlined almost the entire CSS bundle (~37 KB) into every single page. Across 246 pages, that's 7.3 MB of duplicated CSS — a 75x bloat over the actual 99 KB CSS file.

I considered two alternatives:

  1. Adding viewport intelligence to Beasties — This would require running a headless browser during the build to determine which CSS rules are truly above-the-fold. It works, but it makes the build significantly slower (Beasties is already the slowest step in the pipeline).

  2. Disabling Beasties entirely — Pages load CSS via a single external <link> tag. The browser caches it after the first page load. No inlined <style> tags, no duplicated CSS, no build slowdown.

I chose option 2. The CSS file is only 99 KB and compresses well with gzip. Modern browsers handle external stylesheets efficiently — the cache hit rate across pages is excellent.

Info
Note

Turbo mode difference: In --turbo mode, @bdocs/zig-critters (Zig/WASM) handles critical CSS extraction. It's orders of magnitude faster than Beasties and can intelligently extract only the truly critical CSS. If you need critical CSS inlining for performance-sensitive deployments, use --turbo.

Duplicate Locale FixLink

Previously, generateI18nFallbacks() created locale-prefixed copies of the default locale's content. For a site with en (default) and es locales, every English page existed twice:

  • /docs/api/cli — the original
  • /docs/en/api/cli — an identical copy

This resulted in 74 duplicate HTML files totaling ~8 MB of wasted space. The fix skips generating fallback routes for the default locale — its content already exists at the root level.

ResultsLink

MetricBeforeAfterSavings
HTML output (total)25.4 MB~10.1 MB~15.3 MB (60%)
Per-page size (avg)~217 KB~180 KB~37 KB per page
Duplicate pages74074 files eliminated

Other bitsLink

  • Plugin timing visibility — the turbo build now reports per-plugin timing in the build output, so you can see exactly where time is spent
  • Lazy-loaded Sätteri — the Sätteri plugin is dynamically imported on first use, not at startup. If you're not using --turbo, there's zero overhead
  • Cache separation — Sätteri and the default MDX compiler use separate cache namespaces (v6-fallback vs v3). Switching between turbo and non-turbo modes doesn't corrupt cached transforms
  • Beasties fallback — if zig-critters WASM binary is missing, Beasties takes over with a warning. Your build never fails because of a missing binary
  • Duplicate crossorigin fixed — the regex that adds crossorigin to stylesheet links now avoids duplicating the attribute when it's already present
  • PostHog integration — built-in support for PostHog product analytics. Configure via integrations.analytics.posthog with your project API key, and the PostHog snippet is injected automatically. Supports EU cloud, session recording, and autocapture (off by default)

RSS Feed PluginLink

The @bdocs/plugin-rss plugin generates RSS 2.0 and Atom feeds from your documentation routes with zero configuration.

Feeds include all routes by default, organized into a clean rss/ directory:

dist/
  rss/
    feed-en.xml
    feed-es.xml

Quick StartLink

pnpm add @bdocs/plugin-rss
boltdocs.config.ts
import { defineConfig } from 'boltdocs'
import rssPlugin from '@bdocs/plugin-rss'

export default defineConfig({
  siteUrl: 'https://my-docs.com',
  plugins: [rssPlugin()],
})

OptionsLink

OptionTypeDefaultDescription
limitnumberunlimitedMax items per feed (1–500)
pathsstring[]all routesFilter by path prefix
collectionsstring[]all collectionsFilter by collection name
format'rss' | 'atom' | 'both''rss'Feed format(s) to generate

See the full RSS plugin docs for details.


UpgradingLink

No breaking changes. The --turbo flag is opt-in — your existing build command works exactly the same.

To try turbo mode:

pnpm boltdocs build --turbo

If you hit issues, remove the flag. The standard build is unchanged.


Install or update:

pnpm add boltdocs@latest

Check the full docs to explore everything new.

Last updated on July 27, 2026