Docs

CLI

Nifra is zero-config: it reads routes/, framework.ts, and (optionally) backend.ts from your project and wires the right @nifrajs/web entrypoint - no dev.ts/build.ts/server.ts to hand-write. (`create-nifra` scaffolds the conventions.)

TS
nifra dev      # true-HMR dev server (Bun native HMR + Nifra SSR) - http://localhost:4321
nifra dev --vite   # the Vite middleware pipeline instead (automatic when vitePlugins are your ONLY transforms)
nifra build    # full Bun deploy → dist/server.js + content-hashed dist/assets/ (default target: bun)
nifra start    # run dist/server.js on Bun
nifra build --target cf-pages  # also: node | deno | vercel | static; add --report for chunk sizes

# dev + start share the default port 4321. Override per run: --port <n> (alias -p) or the PORT env var.
# flags: --port <n> (dev/start) · --out <dir> (build/start) · --target <t> (build) · --poll (dev)
#        --vite | --bun (dev/build) force the pipeline

The conventions

Four conventions at the project root. nifra dev runs the Bun-native HMR dev server; nifra build runs the Bun-native production build (content-hashed client assets plus a target-specific server); nifra startruns the default Bun output. The generated server serves assets and SSR with matched-route chunks preloaded and route CSS linked in each <head>.

One rule picks the bundler, and it is the same rule in both phases - so a project can never be bundled by one toolchain in dev and the other in production. Bun runs everything, except an app whose only transforms are vitePlugins: the Bun pipeline cannot run those, so that app gets Vite for dev and build alike, and says so. --vite / --bun force the choice; --bun is refused on a Vite-only app rather than dropping its transforms silently. Every dev and build run prints which bundler it picked and why, and nifra check answers the same question without starting a server - see which pipeline runs, when for the full table.

TS
my-app/
  routes/            # file-based routes (index.tsx, _layout.tsx, [id].tsx, …)
  framework.ts       # deploy-safe render adapter
  nifra.config.ts    # CLI-only client module + dev/build plugins
  backend.ts         # export const backend = server()...   (optional - the typed contract)

These paths are fixed, not configurable: the CLI resolves all four from the project root, so backend.ts cannot move into src/ or be renamed - if the file is not at the root, nifra dev|build simply run without a backend (it is optional, so nothing errors). Only the entry file is pinned; the feature modules it .merge()s can live in any directory. Keep backend.ts a pure composition root - merging modules, registering no routes of its own - so each route's capability reach stays its own module's (see Backends & API and Verification).

framework.ts - naming the framework once

Keep the render adapter in deploy-safe framework.ts. Put clientModule, Vite plugins, compiler plugins, conditions, and defines in CLI-only nifra.config.ts. This prevents build tooling and native dependencies from entering generated server bundles.

TS
// framework.ts - deploy-safe; generated server entries import this file.
import { reactAdapter } from "@nifrajs/web-react"

export const adapter = reactAdapter

// nifra.config.ts - CLI-only build/dev tooling; never imported by a deployed server.
// doc-check: skip - needs the third-party @vitejs/plugin-react; install it to run this.
import react from "@vitejs/plugin-react"
export { adapter } from "./framework"
export const clientModule = "@nifrajs/web-react/client"
export const vitePlugins = [react()]          // dev HMR (Fast Refresh)
// Vue/Svelte/Solid also export:
//   clientPlugins = [vueBunPlugin("dom")]     // compile routes for the client build
//   serverPlugins = [vueBunPlugin("ssr")]     // compile routes into the target's server bundle
//   conditions    = ["solid"]                 // Solid: resolve solid-js to its source
//   define        = { __VUE_OPTIONS_API__: "true", ... }   // Vue feature flags

Scope

nifra build defaults to a self-hosted Bun server. Use --target node, deno, cf-pages, vercel, or static for another complete deploy shape (see Deployment). Run non-Bun outputs with the command printed by the build.