Changelog

Self-hosting hardening

  • Fixed
A terminal running the SyntaxKit Docker Compose deploy, with migrations applied, both containers started, and a passing health check

Self-hosted SyntaxKit got a dedicated hardening pass. If you deploy with Docker or Compose, this release fixes a set of problems that ranged from silently-wrong UI to builds that failed outright.

Capabilities are decided at request time

Under Cache Components, a synchronous environment read in a prerenderable position resolves during next build, and the answer gets baked into the static shell. On Vercel that is fine because build env equals runtime env. In the Dockerfile it is not: images build with placeholder credentials, so shells baked in "OAuth disabled", "billing disabled", and kept serving that even after you supplied real keys at runtime.

Capability checks now live in request-scoped loaders that suspend during prerender and resolve on a real request, without blocking prefetches. Login, signup, pricing, contact, billing, and personal settings wrap their capability-dependent markup in Suspense, so a Docker deploy shows OAuth buttons, billing, storage, and the contact form based on the environment the container actually runs with.

Blank env vars no longer break builds

The Dockerfile maps every public build arg to an env var, so an omitted arg arrives as an empty string rather than being unset. The brand package treated empty strings as present and passed them to new URL(""), which had broken every Docker release build since June. URL-shaped values are now trimmed and fall back to defaults when blank, the docs site applies the same handling to its metadata base, and the sitemap and robots routes build crawler URLs from the brand config so they stay absolute.

Compose boots clean

The Compose web service env allowlist gained the Upstash Redis variables (production boots were hitting the config-error screen without them), the Turnstile site key, the public S3 URL, and the three public PostHog variables. The docs Docker image now installs git, so Fumadocs can derive last-modified dates instead of crashing on a missing binary.

Docs roots land on content

The docs site root now redirects to the docs, and locale roots redirect to the right locale's docs root, derived from the shared i18n config, so nobody lands on a dead page.