Agent-native framework · typed APIs · provable security

The AI-Native TypeScript Framework.

Nifra gives agents the live map they need - MCP context, route-aware scaffolds, self-verifying tools, a no-codegen typed client - and a route-assurance gate so nothing they write ships an unproven route. Start with a fast API, grow into SSR across React, Solid, Vue, Preact, or Svelte, and deploy on Bun, Node, Deno, or the edge.

Get started Try the playground

No generated SDK. No stale route docs. No unproven routes. No lock-in.

agent loop
01
nifra_context

Read the live app

Routes, schemas, middleware, and conventions - the real API surface, not stale docs.

02
nifra_scaffold

Write in the right place

URL patterns resolve to framework-correct files, handlers, loaders, and typed clients.

03
nifra_run

Verify the behavior

HTTP, SSR, and WebSocket checks run against the current workspace.

04
nifra_check

Block drift

Typecheck and route-contract checks, with the fix suggested, before CI goes green.

05
nifra_assure

Prove the security posture

Policy classifies every route - an unauthenticated write fails the build, named.

Agents read your live API - and can't ship an unproven routeAn MCP server exposes your real routes and schemas to coding agents, and the assurance gate fails the build if anything they write skips auth or validation.
One schema, everything typedA single schema produces runtime validation, the typed client, OpenAPI, and TypeScript types. Change a route and the frontend stops compiling until you update it.
Ship to any runtimeThe same app runs on Bun, Node, Deno, Cloudflare, and Vercel - switching targets is one line of adapter code.
25×full-stack SSR vs Next.js (Node, dynamic, same machine)
131kreq/s on Bun - 101% of the raw-runtime ceiling, ahead of Elysia
5 + 4UI frameworks · runtimes, from one app
15 KBa typed full-stack base - MCP, WS, SSE, typed client - not just a router
01 · Agent-Native

Your agent reads the live app, not stale documentation.

Run nifra mcp and point Claude Code or Cursor at it: an integrated MCP server plus a conventions file expose your project's live routes, schemas, examples, and drift checks, so the agent reads the real API surface directly. It runs on your machine - your code never leaves it. The docs tools are also hosted at mcp.nifra.dev for agents outside a checkout.

Read about Agent MCP →
TS
$ nifra context        # the project's live API surface - pipe into any agent prompt
  GET  /users/:id   → response { id: string }
  POST /users       body { name: string } → response { id: string, name: string }

$ nifra mcp            # same data as an MCP server - Claude Code & Cursor read it automatically

# The typed client is the safety lock - an agent physically can't call a route that changed:
const res = await api.users({ id: "42" }).get()
if (res.ok) res.data.id
//              ^ tsc error here the moment the route or response shape changes

$ nifra check          # CI gate: typecheck + typed-client lint - drift fails the build
02 · Type-Safe Client

A client that makes API drift a compile error.

No code generators, no build steps, and no stale SDKs. client<typeof app> infers paths, parameters, request bodies, and responses directly from your server type. Any mismatch fails the build.

Explore the Typed Client →
TS
import { client } from "@nifrajs/client"
import type { app } from "./server"   // a type import - server code never ships to the client

const api = client<typeof app>("https://api.example.com")

// The path autocompletes. Params and body are typed. No codegen, ever.
const res = await api.users({ id: "42" }).get()

if (res.ok) {
  res.data.id        // typed from the route return or response schema
} else {
  res.error          // client-call failures are returned, never thrown
}
03 · Unified Frontend

One full-stack engine. Five UI libraries.

React, Solid, Vue, Preact, and Svelte all sit on the same render engine. Loaders, actions, streaming, prefetching, and islands are identical across all five - switching is a single import. No meta-framework lock-in.

Compare the adapters →
TS
// The adapter is the one line that changes per framework:
import { reactAdapter } from "@nifrajs/web-react"
export default createWebApp({ adapter: reactAdapter, manifest, clientEntry })

// routes/hello.tsx - your page, written in React
export function Page({ data }: { data: { name: string } }) {
  return <h1>Hello {data.name}</h1>
}
TS
// The adapter is the one line that changes per framework:
import { solidAdapter } from "@nifrajs/web-solid"
export default createWebApp({ adapter: solidAdapter, manifest, clientEntry })

// routes/hello.tsx - same page, Solid's fine-grained JSX
export function Page(props: { data: { name: string } }) {
  return <h1>Hello {props.data.name}</h1>
}
TS
// The adapter is the one line that changes per framework:
import { vueAdapter } from "@nifrajs/web-vue"
export default createWebApp({ adapter: vueAdapter, manifest, clientEntry })

<!-- routes/hello.vue - same page, as a Vue SFC -->
<script setup lang="ts">defineProps<{ data: { name: string } }>()</script>
<template><h1>Hello {{ data.name }}</h1></template>
TS
// The adapter is the one line that changes per framework:
import { preactAdapter } from "@nifrajs/web-preact"
export default createWebApp({ adapter: preactAdapter, manifest, clientEntry })

// routes/hello.tsx - same page; Preact's 3 KB runtime, identical React API
export function Page({ data }: { data: { name: string } }) {
  return <h1>Hello {data.name}</h1>
}
TS
// The adapter is the one line that changes per framework:
import { svelteAdapter } from "@nifrajs/web-svelte"
export default createWebApp({ adapter: svelteAdapter, manifest, clientEntry })

<!-- routes/hello.svelte - same page, as a Svelte component -->
<script lang="ts">export let data: { name: string }</script>
<h1>Hello {data.name}</h1>
04 · Multi-Runtime

Deploy anywhere. Bun, Node, Deno, or the Edge.

Nifra is built on Web-standard routing and fetch APIs. Run on Bun for blazing-fast development, then deploy to Node, Deno, Cloudflare Workers, or Vercel Edge with a single line of adapter code.

View deployment targets →
TS
import { app } from "./app"   // one app, defined once

// Bun
export default { port: 3000, fetch: app.fetch }

// Node            import { serve } from "@nifrajs/node"   → serve(app, { port: 3000 })
// Deno            import { serve } from "@nifrajs/deno"   → serve(app, { port: 3000 })

// Cloudflare Workers / Pages · Vercel edge
import { toFetchHandler } from "@nifrajs/core/server"
export default toFetchHandler(app)
BunNative dev speedexport default { fetch: app.fetch }
NodeMature, everywhereserve(app, { port: 3000 })
DenoSecure by defaultserve(app, { port: 3000 })
CloudflareWorkers / Pagesexport default toFetchHandler(app)
VercelEdge functionsexport default toFetchHandler(app)
05 · Hardened APIs

Production security built into the framework.

Zero-dependency middleware for security headers, cookies, CSRF, JWT authentication, rate limiting, CORS, and WebSocket topic pub/sub ships in the box. Compose it at the app or route boundary.

View Middleware options →
TS
import { server } from "@nifrajs/core/server"
import { t } from "@nifrajs/schema"

// A typed API - no frontend required. Use Nifra like Hono or Elysia.
export const app = server()
  .get("/users/:id", (c) => ({ id: c.params.id }))
  .post("/users", { body: t.object({ name: t.string() }) }, (c) => {
    // c.body is validated + typed - invalid input is rejected before this runs.
    return { id: crypto.randomUUID(), name: c.body.name }
  })

export default { fetch: app.fetch }   // Bun. Node, Deno, and the edge are one line each.
06 · Route Assurance

Every route proves its security posture - or the build fails.

nifra assure classifies every real route against a policy file and fails CI naming exactly what evidence is missing - an unauthenticated write, an unvalidated body, an undeclared database effect. Linters pattern-match source and spec linters check a document that can lie; this gate reads the live route graph. No other framework ships it.

Read about Assurance →
TS
// nifra.assurance.ts - security posture as policy, not convention
import { defineAssuranceConfig, NIFRA_ASSURANCE } from "@nifrajs/core/assurance"
import { app } from "./src/app"

export default defineAssuranceConfig({
  source: app,
  capabilities: {
    definitions: [{ id: "db.write", zone: "domain", access: "write" }],
    provenance: {
      // Keep the example complete: assurance classification needs both a capability definition
      // and static provenance coverage for the effect it is meant to protect.
      imports: [{ specifier: "./db/write.ts", capabilities: ["db.write"] }],
      forbiddenImports: [],
    },
  },
  policy: {
    rules: [
      {
        // Every domain write must prove authentication - no exceptions, no drift.
        name: "authenticated-write",
        match: { access: "write", zone: "domain" },
        require: [NIFRA_ASSURANCE.AUTHENTICATED],
      },
    ],
  },
})

// $ nifra assure
// ✖ POST /notes (authenticated-write) is missing nifra.authenticated
Ecosystem Packages

A complete framework, batteries included.

Nifra isn't just a router-it's a modular suite of type-safe packages built for high performance, edge scalability, and robust developer ergonomics.

Common combos: auth + uploads for user content · cron + otel for observable background jobs · env + i18n + content for a localized site.

@nifrajs/authBetter-Auth

Session Authentication

First-class integration with Better-Auth. Preconfigured session middlewares, social logins, and typed roles.

import { auth } from "@nifrajs/auth"

export const app = server()
  .use(auth.session())
  .get("/me", (c) => c.session.user)
@nifrajs/uploadsStorage

Direct S3/R2 Uploads

Secure direct-to-cloud file uploads. Generates signed URLs for S3, Cloudflare R2, or Backblaze without proxying heavy buffers.

import { storage } from "@nifrajs/uploads"

const url = await storage.presign("avatars", {
  key: "user-42.png",
  maxSize: "5mb"
})
@nifrajs/cronScheduler

Cron & Background Tasks

Define periodic cron tasks alongside HTTP handlers. Runs on serverless (Cloudflare triggers) and standalone Node/Bun.

import { cron } from "@nifrajs/cron"

export const job = cron("0 0 * * *", async () => {
  await db.sessions.deleteExpired()
})
@nifrajs/otelObservability

OpenTelemetry Tracing

Request tracing and custom spans. Export traces to Honeycomb, Datadog, or Grafana Tempo with zero complex boilerplates.

import { otel } from "@nifrajs/otel"

const app = server()
  .use(otel.trace({ serviceName: "nifra-api" }))
@nifrajs/envValidation

Safe Env Verification

Verify environment variables at startup. Validates that API keys and configurations are present and correctly typed at boot.

import { checkEnv } from "@nifrajs/env"
import { t } from "@nifrajs/schema"

export const env = checkEnv({
  DATABASE_URL: t.string(),
  PORT: t.number({ default: 3000 })
})
@nifrajs/imageMedia

Dynamic Image Optimizer

On-the-fly resizing, WebP/AVIF formatting, quality compression, and CDN caching to optimize LCP load priority.

import { Image } from "@nifrajs/image"

// optimized image component
<Image src="/logo.png" width={800} height={400} priority />
@nifrajs/i18nLocalization

Type-Safe i18n

Dynamic pluralization and translations dictionary with automatic HTTP header language negotiation.

import { i18n } from "@nifrajs/i18n"

const { t } = i18n(c.locale)
return { msg: t("welcome", { name: "Ada" }) }
@nifrajs/contentMDX Engine

MDX Documents Parser

Read Markdown/MDX files, parse frontmatter, validate schemas, and compile them to interactive UI components.

import { content } from "@nifrajs/content"

const posts = await content("posts")
  .where({ status: "published" })
  .all()
@nifrajs/isletsPerformance

Zero-JS Islands

Static HTML pages with dynamic island scripts. Restores client interactivity without large JS hydration overhead.

import { islet } from "@nifrajs/islets"

// zero client runtime by default
export const hydrate = false
export const islandScripts = [counter]

Dependencies Nifra replaces

Each stack on the left is one you would otherwise assemble and keep in sync yourself. Everything else on npm - Stripe, OpenAI, Drizzle, Prisma - needs no integration at all: handlers are plain TypeScript, so it works as-is (see integrations).

API & server
express / fastify / hono@nifrajs/core
helmet + cors + express-rate-limit@nifrajs/middleware
swagger-jsdoc@nifrajs/schema/openapi
Typed client & data
tRPC / OpenAPI client codegen@nifrajs/client
TanStack Query (loader cache + mutations)@nifrajs/web
Background work
BullMQ (single-node jobs)@nifrajs/jobs
node-cron@nifrajs/cron
Files & media
multer@nifrajs/uploads
flydrive (fs + R2 blob storage)@nifrajs/storage
sharp + srcset glue (responsive images)@nifrajs/image
App services
dotenv + envalid@nifrajs/env
keyv / node-cache@nifrajs/cache
i18next (locale + ICU formatting)@nifrajs/i18n
contentlayer@nifrajs/content
Testing & mocks
supertest@nifrajs/testing
json-server (contract mocks)@nifrajs/mock
Performance & Speed

Screamingly fast, frontend and backend.

Nifra runs close to raw Bun/Node speed. Full-stack SSR renders 3.9× to 25× faster than standard meta-frameworks on Node, while the backend router matches the fastest Node frameworks - tens of thousands of requests per second on a single core.

Full-stack SSR · req/sReact, rendered per request - Nifra (Bun + Node) vs Next.js + Remix
Nifra + React (Bun)33,834
Nifra + React (Node)28,043
Next.js (Node)1,115
Remix (Node)2,103
Node Frameworks · req/sJSON GET /users/:id · Same machine throughput
Nifra92,120
Fastify71,589
Hono52,255
Express51,796

See detailed memory, cold-boot, and payload size metrics on the benchmarks page.

The Anti-Drift Lifecycle

One schema is the single source of truth.

Define a contract once. Nifra keeps validation, types, the typed client, OpenAPI, and your agents in sync with it across the stack.

t.object({…})one schema
Runtime validationBad input → 422 before your handler
TypeScript typesInferred params, body, response
Typed clientNo codegen - drift is a compile error
OpenAPI specGenerated, never hand-written
MCP toolsAgents read the live contract
01
@nifrajs/schema

Define the Data Contracts

Model request inputs and response payloads with compiled validation. A single schema handles runtime validation, exports TypeScript types, and builds OpenAPI specifications automatically.

TS
import { t } from "@nifrajs/schema"

// A contract schema for your routes
export const GetUserSchema = {
  params: t.object({ id: t.string() }),
  response: t.object({
    id: t.string(),
    name: t.string(),
    role: t.union([t.literal("admin"), t.literal("user")])
  })
}
02
@nifrajs/core/server

Mount the Typed Router

Implement the endpoint. Path parameters are automatically parsed from the literal path, and the incoming request body and query parameters are typechecked at the runtime boundary.

TS
import { server } from "@nifrajs/core/server"
import { GetUserSchema } from "./schema"

export const app = server()
  .get("/users/:id", GetUserSchema, (c) => {
    // c.params.id is typed as string
    return { id: c.params.id, name: "Ada", role: "admin" }
  })
03
@nifrajs/client

Call from Frontend (No-Codegen)

Build the client using only the server's type signature. Autocomplete handles the paths, parameters, and payloads, while TypeScript ensures the frontend never goes out of sync with the backend.

TS
import { client } from "@nifrajs/client"
import type { app } from "./server"

const api = client<typeof app>("https://api.example.com")

// Typed call, autocompleted paths, compile-time checked
const res = await api.users({ id: "123" }).get()
if (res.ok) console.log(res.data.name)
04
nifra mcp

Feed AI Agents Live Context

Coding agents write better code when they know the actual codebase rules. Nifra feeds Claude Code, Cursor, or Copilot your live routes and call signatures directly through a Model Context Protocol (MCP) server.

Shell
# Run once to register the Nifra MCP server with Claude Code
$ claude mcp add nifra -- bunx nifra mcp

# Claude can now query:
# - nifra_context (live routes & schemas)
# - nifra_run (in-process verification)
05
nifra check

Enforce Seams in CI

Block breaking changes from merging. The Nifra linter analyzes client-server bindings and flags frontend-backend drift in a single command, keeping your pipeline green.

Shell
# Run linter and typecheck in your GitHub actions
$ nifra check

# Fails CI if a route signature was changed on the backend
# but remains un-updated on the frontend client.
Ready when you are

Build something that survives the next AI edit.

One command scaffolds a typed Nifra app - start as a fast API, grow into full-stack SSR, and let your agents read the live contract instead of guessing.

Get started See the benchmarks