Type-Safe File-Based REST API Router

Define schemas once.
Let types cascade everywhere.

File-based routing for TypeScript REST APIs. Compose scoped directory middleware with full type inference, enforce compile-time return contracts, and eliminate type assertions forever.

import { json } from '@taserjs/router/reply'import { t } from '@taserjs/router'export default t.get('/dashboard').handler(async ({ ctx, state }) => {  const { user } = state // state -> { user: User }  const stats = await ctx.db.getDashboardStats(user.id)  return json({    greeting: `Welcome back, ${user.name}`,    user,    stats,  })})
E2E Type Safe

Agent Skills

Supercharge your AI agent with official Taser.js Skills

Equip Cursor, Claude Code, Windsurf, Copilot, Cline, and Codex with deep knowledge of Taser.js file conventions, cascading layouts, Standard Schema validation, and client RPC.

AI Agent Quickstart Guide
Open Agent Skill
1Install the Skill
$npx skills add taserjs/taserjs

Run this command in your repository root to register Taser.js rules and decision workflows directly with your local coding assistant.

Works out of the box with:
CursorClaude CodeWindsurfGitHub CopilotClineCodex
2Ask Your AI Assistant

“Set up Taser.js API routes in my Next.js project with Zod validation, a protected layout, and a typed client”

The skill ensures the Agent follows the Taser.js conventions and best practices.

The Problem & Solution

Why traditional Node.js routing breaks at scale

Traditional routers force trade-offs between clean folder structures and real type safety. Taser.js eliminates the type assertion trap and guarantees runtime correctness from middleware to client.

Traditional API (Express / Fastify)
Type Casting Required
server.ts
// Middleware attaches data to reqapp.use((req, res, next) => {  req.user = getUser(req); // untyped assignment  next();});// Downstream handler has NO type inferenceapp.post("/private", validateBody(schema), (req, res) => {  const user = req.user as User;       // ⚠️ manual typecast  const body = req.body as PostBody;   // ⚠️ manual typecast  const query = req.query as Query;    // ⚠️ manual typecast  res.send({ ok: true });});
Taser.js Router
100% Inferred State
routes/admin.ts + routes/admin/reports.post.ts
// Middleware validates and passes state via next()export default t.layout("/admin/*").use(async ({ req, ctx }, next) => {  const token = req.headers.get("authorization");  const user = await verifyUser(token);  if (!user) throw new Error("Unauthorized");  return next({ user }); // Merges into state});// Handler receives fully-inferred facets automaticallyconst POST = t.post("/admin/reports").body(ReportInputSchema);export default POST.handler(async ({ req, state }) => {  const user = state.user; // ✓ Inferred User from next({ user })  const body = req.body;   // ✓ Inferred ReportInput  return json({ created: true, by: user.id });});
Key Takeaway: In Taser.js, middleware return state flows into the state facet with zero typecasting or Express global interface hacks.

Mental Model

Inspired by TanStack Router. Engineered for REST APIs.

TanStack Router revolutionized client routing with file-system layouts and type inference. Taser.js brings that same intuition to backend HTTP servers: HTTP verb files for handlers, non-verb files for cascading directory middleware.

Taser.js Router
Backend REST API
File StructureTypeMatched Endpoint
$.ts
MW
/*
index.get.ts
GET
/
posts.ts
MW
/posts/*
posts
/posts
index.get.ts
GET
/posts
index.post.ts
POST
/posts
$postId.get.ts
GET
/posts/$postId
_auth.ts
MW
/posts/*
_auth
/posts
$postId.put.ts
PUT
/posts/$postId
$postId.delete.ts
DELETE
/posts/$postId

How the mental model translates to the backend

In Taser.js Router, files are treated differently depending on their suffix:

HTTP Verb Files(Handlers)

Endpoints are segregated by method suffixes: .get.ts, .post.ts, .put.ts, .delete.ts, .patch.ts, and all standard HTTP verbs.

Non-Verb Files(Middleware)

Files without a verb (e.g. $.ts, posts.ts, _auth.ts) act as scoped middleware. They run before child handlers and cascade typed context down the folder tree.

Quick Start

Scaffold your stack in seconds

Interactive CLI with batteries included: pick your framework, Nitro preset, database ORM, Standard Schema validator, and logger.

bash — create-taserjs
create-taserjsv0.0.1
◇Project name
my-api
◇Host framework
● None (Standalone)○ Hono / Fetch-Native○ Express○ Fastify
◇Deployment target (preset)
● Node Server○ Node Cluster○ Standalone Vite○ Bun○ Deno Server○ Deno Deploy○ Cloudflare○ Vercel○ AWS Lambda○ Netlify
◇Database
● Drizzle○ Prisma○ Kysely○ None
◇Database driver
○ PostgreSQL● SQLite○ MySQL
◇Logger
● Pino○ Winston○ None
◇Validator
● Zod○ ArkType○ Valibot
✔Scaffolded ./my-api successfully!
Created None (Standalone) app targeted for Node Server with Drizzle (SQLite), Zod validation, and Pino logging.

Configure Your Stack

One-Liner Command
pnpm create taserjs@latest my-api --framework none --preset node-server --db drizzle:sqlite --logger pino --validator zod -y

Run this command to bypass interactive prompts and generate your project instantly in CI or your terminal.

Roadmap

What the future looks like

We're actively building the next generation of type-safe backend tooling. Here is what is on our horizon.

In Development

OpenAPI Specification Generation

Auto-generate OpenAPI 3.1 YAML and JSON endpoints directly from your file routes, Standard Schema definitions, and return contracts. Zero manual Swagger spec writing.

OpenAPI 3.1 YAML/JSONSwagger UI endpointZero schema duplication
In Development

ESLint Plugin for Router Rules

Dedicated @taserjs/eslint-plugin to enforce HTTP verb suffixes (.get.ts, .post.ts), catch invalid param patterns, and validate route exports right in your editor.

File naming linterExport contract checksCLI & CI/CD guards
Planned

WebSockets & Server-Sent Events

Realtime streaming routes (.ws.ts, .sse.ts) with typed event schemas, connection lifecycle hooks, and bi-directional type safety for live updates.

.ws.ts & .sse.ts file routesTyped event channelsStreaming client SDK
Planned

Distributed Rate Limiting & Observability

Distributed Redis sliding-window rate limiting, OpenTelemetry distributed tracing spans, Prometheus metrics exporters, and automated ETag cache middleware.

Distributed Rate LimitingOpenTelemetry TracesETag & Cache Controls

Open Source & Independent

Backed by the community. Built for everyone.

Taser.js is 100% open source. Sponsoring funds continuous performance optimizations, runtime adapter development, codegen tooling, and long-term maintenance.

Sponsor Taser.js Development

Support sustainable open source tooling. Contributions directly support new runtime adapters, compiler features, instant watch-mode codegen, and Standard Schema integrations.

Get Started

Ready to ship type-safe REST APIs?

Explore the documentation, pick your framework adapter, and build handlers with zero manual route registries and zero type casting.

Read the Documentation
Kazi Ahmed

Kazi Ahmed

Creator

Crafting type-safe developer tools, runtime adapters, and deterministic routing engines for TypeScript.