Agent-native framework · typed APIs · verified edits

The AI-Native TypeScript Framework.

Nifra gives agents the live map they need: MCP context, route-aware scaffolds, self-verifying tools, and a no-codegen typed client. 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 framework lock-in.

agent loop
01
nifra_context

Read the live app

Routes, schemas, middleware, package versions, and project conventions in a compact payload.

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, WebSocket, and subprocess checks run against the current workspace.

04
nifra_check

Block drift

Typecheck, route-contract checks, and conservative fix suggestions before CI goes green.

Agents read your live APIAn MCP server exposes your real routes and schemas to coding agents; a typed client lets them call those routes with full autocomplete.
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.
22×full-stack SSR vs Next.js (Node, dynamic, same machine)
120kreq/s on Bun — 103% of raw, ahead of Hono & 95% of Elysia
5 + 4UI frameworks · runtimes, from one app
8.2 KBgzipped server — cookies, logger & graceful shutdown included
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.

Read about Agent MCP →
TS
$ nifra context        # the project's live API surface — pipe into any agent prompt
  GET  /users/:id   → response { id: string, name: 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.name
//              ^ 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.name      // 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"
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"
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.
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]
Performance & Speed

Screamingly fast, frontend and backend.

Nifra runs close to raw Bun/Node speed. Full-stack SSR renders 3× to 22× 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/sDynamic SSR rendering (Nifra on Node vs Meta-frameworks)
Nifra + React (Bun)31,800
Nifra + React (Node)22,714
Next.js1,038
Nifra + Solid (Bun)30,400
Nifra + Solid (Node)21,712
SolidStart6,430
Node Frameworks · req/sJSON GET /users/:id · Same machine throughput
Nifra77,561
Fastify77,091
Express50,996
Hono50,727

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 → 400 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

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"
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
Proudly built with Nifra — server-rendered on Cloudflare Pages.MIT