Docs

Deployment

app.fetch(request) is a pure Web-standard handler, so the same app runs anywhere. Pick a runtime; the code doesn't change.

One command per target

create-nifra's site template ships every target's build + server entry and config. Pass --deploy <target> to make one the default — it points build/deploy at that target and fills in your project name. The per-target build:*/deploy:* scripts stay, so you can switch any time.

TS
# Scaffold the multi-target site with a chosen default deploy target:
bun create nifra my-app --deploy vercel     # or: bun | node | deno | cf-pages
# add --framework to pick the UI too (react default):
bun create nifra my-app --framework svelte --deploy vercel

cd my-app && bun install
bun run dev       # local preview
bun run build     # builds for the chosen target
bun run deploy    # runs that target's deploy CLI (you stay logged-in to the vendor)

# Or add --ci github to also emit a deploy-on-push GitHub Actions workflow:
bun create nifra my-app --deploy cf-pages --ci github
#   → .github/workflows/deploy.yml (builds on every push/PR, deploys on push to main)
targetbuild →deployconfig scaffolded
Bun (flagship)dist-bun/bun run start (any host)
Nodedist-node/docker build … && docker runDockerfile + .dockerignore
Deno Deploydist-deno/deployctl deploydeno.json
Cloudflare Pagesdist/wrangler pages deploywrangler.toml
Vercel Edge.vercel/output/vercel deploy --prebuiltBuild Output API v3

Nifra never runs the deploy or enters your cloud credentials — it scaffolds the config + a deploy script that shells out to the vendor CLI you've already authed.

CI: deploy on push

Add --ci github to emit a .github/workflows/deploy.yml tuned to the chosen target — it builds on every push/PR and deploys on a push to main. cf-pages uses cloudflare/wrangler-action, vercel the prebuilt vercel deploy, deno deployctl (OIDC). The workflow's header comment lists the exact repo secrets to set (e.g. CLOUDFLARE_API_TOKEN, VERCEL_TOKEN). Self-hosted bun/node have no universal push-to-deploy, so their workflow builds + uploads the bundle as an artifact and leaves a clearly-marked, host-specific deploy step for you to fill in (Fly, a registry push, SSH, …).

Bun (its home)

app.listen(3000) — the native Bun server. Sits at the raw Bun.serve ceiling (see benchmarks).

Every core: Bun is single-threaded per process — for multi-core boxes, spawn one process per core, each binding the same port with app.listen(PORT, { reusePort: true }); the kernel load-balances connections across them (Linux balances ~evenly). A supervisor that spawns + restarts workers is ~20 lines — see examples/cluster.ts. Anything shared across workers (rate limits, sessions, pub/sub) needs a shared store, as in any multi-instance deploy.

Node & Deno

  • @nifrajs/nodeserve(app, { port }) bridges to node:http.
  • @nifrajs/deno — serves app.fetch on Deno.serve.

Self-hosting (no CDN in front)? Hand @nifrajs/node's serve a static mount and it serves the client bundle from disk — traversal-guarded, content-typed, with an immutable cache — before the app runs, leaving the SSR fast path untouched: serve(app, { port, static: { dir: new URL("./assets/", import.meta.url) } }). On Cloudflare/Vercel the platform serves assets, so you don't need it there.

Cloudflare Workers / Pages (the edge)

buildServer bundles with edge conditions (workerd, edge-light) into a _worker.js; toFetchHandler(app) is the handler. For Pages, a _routes.json serves the client bundle statically. SSR verified on real workerd — this very site runs there.

TS
// _worker.ts — the edge SSR entry
import { toFetchHandler } from "@nifrajs/core"
import { createWebApp } from "@nifrajs/web"
import { reactAdapter } from "@nifrajs/web-react"
import { clientEntry, manifest } from "./server-manifest"  // generated by buildServer

const app = createWebApp({ adapter: reactAdapter, manifest, clientEntry })
export default toFetchHandler(app)   // a Workers/Pages fetch handler

// build.ts — buildClient (→ /assets) + buildServer (edge conditions → _worker.js)
import { buildClient, buildServer } from "@nifrajs/web/build"

Deploy: wrangler pages deploy dist (Pages) or wrangler deploy (Workers). Deno Deploy and Vercel Edge reuse the same build with their conditions.

Proudly built with Nifra — server-rendered on Cloudflare Pages.MIT