SST.dev

How Nuxfire uses SST to define its Cloudflare infrastructure as code, and what a stage actually is.

SST is the infrastructure-as-code layer Nuxfire is built on. Every Cloudflare resource — Workers, Hyperdrive, KV, R2, D1, Queues, Durable Objects, Cron, DNS — is a sst.cloudflare.* (or plain sst.*) resource declared in TypeScript under infra/, never a hand-written wrangler.toml/wrangler.json and never a wrangler deploy called outside SST.

How the pieces load

sst.config.ts is the entry point. Its run() doesn't list resources itself — it reads every .ts file in infra/ and imports it, merging each file's outputs export into the stack's outputs:

sst.config.ts
async run() {
  const outputs = {};
  for (const value of readdirSync("./infra/").filter((x) => x.endsWith(".ts"))) {
    const result = await import("./infra/" + value);
    if (result.outputs) Object.assign(outputs, result.outputs);
  }
  return outputs;
},

So infra/database.ts, infra/auth.ts, infra/app.ts, infra/jobs.ts, infra/websockets.ts, infra/cron.ts, infra/web.ts, infra/emails.ts, infra/dns.ts, and infra/secret.ts are each just a module that declares its own resources — there's no central "stack" file to keep in sync.

home: "cloudflare" in the same config means SST's own state (what's deployed, resource IDs) is stored in your Cloudflare account, not AWS — no separate AWS account is needed anywhere in this setup.

Stages

A stage is an isolated, named deployment — its own Workers, its own database connection, its own secrets. infra/dns.ts is what turns a stage name into a domain:

infra/dns.ts
export const domain =
  $app.stage === "production"
    ? branding.domain
    : `${$app.stage}.dev.${branding.domain}`;

The stage named production maps to your BRAND_DOMAIN (the Branding section of the stage's env file, read by scripts/branding.ts); every other stage name maps to <stage>.dev.<BRAND_DOMAIN> — which is why bun run deploy with no flags, run by a developer named alex, deploys to alex.dev.yourdomain.com.

Only production also serves www.<BRAND_DOMAIN>: webAliases in infra/dns.ts attaches it to the Web Worker as a second Workers Custom Domain, so visitors stay on www while the site's canonical, og:url and hreflang tags (built from SITE_URL) point at the apex. It is deliberately not a 301: SST's redirect option relies on Page Rules, which Cloudflare's API does not accept for Account API Tokens. Before the first deploy, www (and the apex) must have no existing A, AAAA or CNAME record in the zone — Cloudflare rejects a Workers Custom Domain on a hostname that already has one (error 100117).

sst.config.ts also treats production differently on purpose:

sst.config.ts
removal: input?.stage === "production" ? "retain" : "remove",
protect: ["production"].includes(input?.stage),

Every other stage's resources are torn down on sst remove; production's are retained and protected from accidental removal.

Secrets

Every sst.Secret Nuxfire declares lives in infra/secret.ts, scoped per stage — loading a value into your personal dev stage never touches production's vault, and vice versa. See Secrets for the exact sst secret load workflow, and note the one exception: CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID are never sst.Secrets — SST needs them as real shell environment variables before it can even authenticate to read the vault.

Deploying

bun run deploy                          # your personal dev stage
bun run deploy -- --stage production    # production
bun run deploy -- --stage custom-name   # any other named stage

bun run deploy (scripts/deploy.ts) runs the preflight check (scripts/doctor.ts, also available alone as bun run doctor) and then sst deploy, passing the same arguments to both; the -- is required for the --stage flag to reach them rather than being swallowed by bun run. Calling sst deploy directly works too, but skips the preflight.

Nuxfire Production Kit

Ready to build and launch your SaaS?

Get 100% full source code ownership, zero proprietary wrappers, and architecture engineered for millions of requests on Cloudflare.

© 2026 Nuxfire