Skip to content
brust

A brust app deploys in one of two shapes: a server — the brust build output running under Bun — or a static export when every route can be prerendered. This page covers the server path and points to the Markdown Pages guide for static.

What brust build produces

brust build compiles the app into a self-contained dist/ (see the CLI reference for all flags):

Output What it is
index.js The bundled server entry (Bun.build, ESM, react/react-dom external).
native/brust.<target>.node The Rust server + compiler binary, one per selected --target.
jinja/ Compiled native templates (TSX pages and markdown pages alike).
islands/ Prebuilt island chunks, the hydration bootstrap, and behavior-directive chunks.
css/ Tailwind output (app.css) and component CSS-module chunks.
public/ Your static assets, copied verbatim.
mcp-manifest.json The extracted agent surface.
md-manifest.json Frozen markdown route table — only when the app has mdRoutes.
static/ The prerendered site, only with --ssg.

Native targets

The .node binary is platform-specific. --target controls which one(s) the build copies in:

Value Meaning
auto (default) The machine you are building on.
all Every available platform binary.
explicit list Comma-separated <platform>-<arch>[-<libc>] values.

The six published targets: darwin-x64, darwin-arm64, linux-x64-gnu, linux-arm64-gnu, linux-x64-musl, linux-arm64-musl. Cross-building for a target requires its brustjs-<target> package to be installed — build on CI matching your deploy platform, or --target all from a machine that has them.

Running the server

bun dist/index.js

Run from the project root with dependencies installed: react and react-dom are deliberately not bundled into index.js (bundling a second copy would split React across two instances and break island SSR), so they resolve from node_modules at runtime. The dist bundle marks itself prebuilt — boot skips template compilation, island bundling, and manifest extraction and serves straight from the dist/ artifacts.

Configuration

Precedence, low → high: framework defaults < values passed to brust.run() < brust.toml < environment.

Env var brust.toml Default Meaning
BRUST_ADDR [server] address localhost Bind address — set 0.0.0.0 in a container.
BRUST_PORT [server] port 1337 TCP port.
BRUST_WORKERS [workers] count one per CPU Render worker (Bun thread) count.
BRUST_RENDER_SLOTS 1 Concurrent in-flight renders per worker.
[cache] max_entries 1000 Response-cache capacity (entries).
BRUST_DEV off 1 forces dev mode — never set in production.
# brust.toml
[server]
address = "0.0.0.0"
port = 8080

[workers]
count = 4

Sizing workers

The default — one worker per CPU — is right for the typical case. React rendering is CPU-bound: raising the count above the core count oversubscribes and amplifies p99 latency rather than adding throughput. The knob that helps is workload-dependent:

  • Native-route-heavy apps render in Rust; workers only run loaders, so the default is already generous.
  • Suspense- or loader-bound React SSR (renders that spend their time awaiting I/O) benefits from BRUST_RENDER_SLOTS > 1 — multiple renders interleave on one worker while each waits — before it benefits from more workers.

Static deploys

If every route is statically renderable, skip the server entirely: brust build --ssg crawls the built app into plain HTML + assets that any static host serves — including per-route SPA payloads, so client-side navigation keeps working without a server. Dynamic-param, wildcard, SSE, and WebSocket routes are excluded, any non-200 fails the build, and the export must live at a domain root. The full walkthrough, including Cloudflare Pages settings, is in Markdown Pages → Static export.

Next

Every command and flag, verbatim: CLI.