Introduction

High-performance, file-based REST API router for TypeScript. Zero runtime drift, cascading middleware context, and automatic client generation.

Taser.js is a modern, type-safe, file-based router designed for scalable Node.js and edge HTTP services. It bridges the gap between clean filesystem architecture and strict type safety.

Traditional Node.js routing forces you to write manual route registries, perform unsafe type assertions on req.user, and maintain separate client types that drift over time. Taser.js solves these challenges by treating the filesystem as the source of truth, cascading middleware state through directory layouts, and generating a 100% typed client SDK.

Layout Middleware

src/routes/users.ts
import { t } from "@taserjs/router";
import { unauthorized } from "@taserjs/router/reply";

// Applies to all routes under /users/*
export default t.layout("/users/*").use(async ({ req, ctx }, next) => {
  const token = req.headers.get("authorization")?.replace(/^Bearer\s+/i, "");
  const user = token ? await ctx.db.findUserByToken(token) : null;
  if (!user) {
    return unauthorized({ message: "Unauthorized" });
  }
  return next({ user });
});

Route Handler

src/routes/users/$id.get.ts
import { json, notFound, forbidden } from "@taserjs/router/reply";
import { z } from "zod";
import { t } from "@taserjs/router";

const GET = t
  .get("/users/:id")
  .params(z.object({ id: z.string().uuid() }))
  .query(z.object({ includeProfile: z.coerce.boolean().default(false) }));

export default GET.handler(async ({ req, ctx, state }) => {
  // req.params.id is typed as string (UUID)
  // req.query.includeProfile is typed as boolean
  // state contains data injected by layout middlewares
  const isAdmin = await ctx.db.isUserAdmin(state.user.id);
  if (!isAdmin) {
    return forbidden({ message: "Forbidden" });
  }

  const user = await ctx.db.findUserById(req.params.id);
  if (!user) {
    return notFound({ message: "User not found" });
  }

  return json(user);
});

Route Path Strings Are Generated Automatically

The path string passed to t.get(), t.post(), t.layout(), etc. is generated automatically by the dev watcher (vite dev, next dev) or @taserjs/cli when route files are first created (e.g. via touch src/routes/...). You do not need to author this string by hand.


Why Taser.js?

Deterministic File Routing

Drop .get.ts, .post.ts, or .put.ts files into your routes directory. Routes, parameters, and splats are discovered automatically with virtual module HMR.

Cascading Context Inference

Middleware state declared in folder layouts flows into the state facet for child routes with zero typecasting or global namespace pollution.

Compile-Time Return Contracts

Declare response schemas with .returns(). The TypeScript compiler verifies that your handler return shapes match your published API contracts.

Standard Schema Validation

Validate query parameters, path params, headers, and request bodies using Zod, ArkType, Valibot, or any Standard Schema library.

Vite Native & Nitro Presets

Vite-native development with virtual routing and instant HMR. Deploy anywhere using Nitro multi-cloud presets, or embed inside Next.js and host apps.

Zero-Drift Typed Client

Export your router type and call your backend using an auto-completing, fully typed client that guarantees 1:1 parity with server endpoints.


How Taser.js Works

Taser.js operates around a deterministic, fully type-safe request lifecycle:

Taser.js Request Execution Pipeline

Click any stage to inspect lifecycle execution, data flow, and type inference

Stage 01RUNTIME

TaserApp Dispatch

@taserjs/plugin and @taserjs/cli emit a static route manifest into routes.gen.ts. createTaserApp() registers composed handlers on a Hono TaserApp once; each request is served via the Web fetch API with no filesystem routing at runtime.

Execution Highlights
Generated Entry: src/.taserjs/routes.gen.ts exports app and AppManifest
Host Integration: Standalone Vite/Nitro, Next.js plugin, or host pass-through (Express, Fastify, Hono)
Dispatch: await app.fetch(request) → Web Standard Response
src/.taserjs/routes.gen.tsTypeScript
// createTaserApp(routeManifest, taser) at build time
export const app = /* Hono TaserApp */

// Per request (any host):
const response = await app.fetch(request)
1 of 7

Vite-Powered Virtual Modules

Taser.js integrates with Vite via @taserjs/plugin/vite. Routes are loaded virtually during development with instant HMR and bundled into optimized production artifacts via Nitro deployment presets.


Scaffold with create-taserjs

Get up and running in seconds using the official scaffolding CLI. Customize your stack across five modular dimensions:

  • Host Framework: Standalone Taser.js (none), hono, express, or fastify.
  • Deployment Preset: node-server, node-cluster, bun, deno-server, deno-deploy, cloudflare-module, vercel, aws-lambda, netlify, or standalone Vite (none).
  • Runtime Override: Explicit node or bun execution target for self-hosted presets.
  • Database & Driver: Drizzle, Prisma, or Kysely with SQLite, PostgreSQL, or MySQL drivers (--db <odm>:<driver>).
  • Standard Add-ons: Zod, ArkType, or Valibot for schema validation; Pino or Winston for structured logging.
pnpm create taserjs@latest my-api

For full flag definitions and project structure options, see the Quickstart Guide.


AI Agent Skill

Equip your AI coding assistant (Cursor, Claude Code, Windsurf, GitHub Copilot, Cline, Codex) with expert knowledge of Taser.js file routing conventions, cascading layouts, Standard Schema validation, and typed client RPC.

Install the official skill using the open agent skills CLI:

npx skills add taserjs/taserjs 

What the Skill Teaches Your Assistant

  • Filesystem Conventions: Eliminates hallucinated routes by strictly adhering to verb suffixes (.get.ts, .post.ts), dynamic parameters ($id), splats ($), and layout middleware.
  • Layout and Middleware Inheritance: Guides assistants to declare cascading layouts and middleware that flow into child routes via state without unsafe type assertions.
  • Validation & Return Contracts: Guides assistants to declare schemas with Zod, ArkType, or Valibot while pairing status codes with standalone reply helpers (json, created, notFound).
  • Host Migrations & Client RPC: Guides incremental migrations from Express, Fastify, and Hono using host pass-through adapters and generates typed @taserjs/client calls.

Example Prompts

Once installed, your AI assistant will reference Taser.js rules automatically. Try prompts like:

"Set up Taser.js API routes in my Next.js project with Zod schema validation, an auth layout, and a typed client."
"Create a type-safe POST /api/users endpoint in Taser.js with body validation and compile-time return contracts."
"Migrate my existing Express routes to Taser.js using host pass-through without breaking current APIs."

Quick Navigation

Explore the documentation to start building or migrating your existing server: