Skip to content

The first TypeScript REST API framework built for secure AI-assisted services

DaloyJS combines runtime portability, contract-first OpenAPI, generated typed clients, zero-dependency runtime guardrails, and supply-chain-aware project defaults in one framework.

contract flowdefine once -> generate the rest
01contractGET /books/:id + z.object(...)
02validationruntime, both directions
03OpenAPI 3.1live spec + /docs UI
04typed clientpnpm gen -> fetch SDK

Any framework can route a request. DaloyJS is built for what happens next: one route definition drives validation, types, OpenAPI 3.1, and a Hey API typed client, and the guardrails AI-assisted code forgets (rate limits, body limits, timeouts, prototype-pollution-safe parsing) ship already switched on. One line on the App constructor, docs: true: auto-mounts a Scalar API reference at /docs and the live OpenAPI 3.1 spec at /openapi.json, the same DX as FastAPI.

ᜇᜎᜓᜌ᜔ Daloy means flow in Tagalog, pronounced da-loy. About the name

New to backend TypeScript? Start with the bookstore tutorial. Evaluating options for a team? Everything below answers one question: what does DaloyJS have that the others don't?

$ pnpm create daloy@latest my-api
2,357/2,357 tests passing≥90% line/function and ≥92% branch coverage gates0 runtime dependenciesNode 24 LTS, Node 26+, Bun, Deno, CloudflareMIT licensed

Why DaloyJS

There are plenty of good ways to route an HTTP request in JavaScript. This is what the others don't give you: secure by default at the runtime layer, pnpm install-time hardening shipped with create-daloy, and an optional hardened GitHub Actions bundle, so the app-safe pieces of the LLM-era supply-chain defense are on the happy path without giving up OpenAPI ergonomics, runtime portability, typed clients, or Node ops.

Secure-by-default runtime
Unlike frameworks that leave basic protections to plugins or manual error routing, the DaloyJS core starts with guardrails on: prototype-pollution-safe JSON, built-in load shedding, proper 405 Method Not Allowed responses, automatic 5xx info-disclosure stripping in production, and a rate-limited CSP violation receiver.
Zero runtime dependencies
Installing @daloyjs/core adds exactly zero transitive packages. No postinstall scripts to audit, no surprise CVEs from dependencies you never chose, and nothing for a slopsquatter to impersonate: the smallest supply-chain surface a framework can ship.
Supply-chain-hardened scaffolds
Pick pnpm in create-daloy and the hardened .npmrc is already written: ignore-scripts=true blocks malicious post-install payloads, minimum-release-age=1440 waits out fresh-package attacks, and verify-store-integrity keeps installs honest. The optional security bundle adds hardened GitHub Actions, Dependabot, CODEOWNERS, SECURITY.md, lockfile source verification, non-root + tini container templates, and a daloy doctor production-posture validator.
AI-native scaffolding
Every project scaffolded by create-daloy includes an AGENTS.md and context skills, and these docs are readable over MCP. Copilot, Claude, and Cursor automatically understand your framework's conventions, routing rules, and security primitives without a prompt-engineering ritual.
Contract-first by design
One route definition is the source of truth for validation, types, OpenAPI 3.1, the typed client, and built-in contract tests, so drift has fewer places to hide.
Runtime-portable
The core only sees Request → Response. Adapters live at the edge: Node, Bun, Deno, Cloudflare Workers - same app, same tests, five runtimes.
Hey API typed clients
Run pnpm gen and get a fully typed fetch SDK, for any consumer, in any TS project, generated from your real spec. Or skip codegen with the in-process typed client.
Streaming & observability
Backpressure-safe SSE and NDJSON helpers, plus an OpenTelemetry tracing hook that emits HTTP server spans with semantic-convention attributes.
Batteries included
Edge-friendly sessions, WebSockets that spend from the same rate-limit buckets as HTTP, structured logs, and graceful shutdown: the production plumbing you usually assemble from plugins, still with zero runtime dependencies.

Hello, contract

One route, types, validation, OpenAPI, and the typed client all generated from it.

ts
import { z } from "zod";
import { App, secureHeaders, rateLimit, requestId } from "@daloyjs/core";
import { serve } from "@daloyjs/core/node";

const app = new App({ bodyLimitBytes: 1 << 20, requestTimeoutMs: 5_000 });

app.use(requestId());
app.use(secureHeaders());
app.use(rateLimit({ windowMs: 60_000, max: 120 })); // global unless you configure keyGenerator or trustProxyHeaders

app.get(
  "/books/:id",
  {
    request: { params: z.object({ id: z.string() }) },
    responses: {
      200: { description: "Found", body: z.object({ id: z.string(), title: z.string() }) },
      404: { description: "Not found" },
    },
  },
  async ({ params }) => ({
    status: 200,
    body: { id: params.id, title: `Book ${params.id}` },
  }),
);

serve(app, { port: 3000 });

Scalar API reference, one line

Scalar is the modern successor to Swagger UI: fast, clean, dark-mode-native, with built-in try-it requests. In DaloyJS it is the default docs UI, not a plugin: docs: true on the App constructor auto-mounts this page at /docs and the live OpenAPI 3.1 spec at /openapi.json.

Generated from your route contracts, zero extra code. Prefer Swagger UI or Redoc? Both are one config field away. OpenAPI & docs UI guide →

Competitor strengths, fewer tradeoffs

DaloyJS is not trying to win one checkbox. It is trying to remove the glue work between the best ideas developers already like.

You wantToday's best-ofWhat DaloyJS gives you
Best OpenAPI ergonomicsFastAPIBuilt-in OpenAPI 3.1 from one route definition
Serverless / edge fitHonoWeb-standard core, multi-runtime adapters
Mature Node ops & docsFastifyEncapsulated plugins, structured logs, graceful shutdown
Modern TS-first DX, Bun OKElysiaEnd-to-end typed handlers, typed context, typed client
Best typed client codegenHey APIpnpm gen → fully typed fetch SDK
Portable supply-chain hardening for the apps you buildpnpm defaults + zero-runtime-dep coreHardened .npmrc, source-verified lockfiles, SBOM + npm provenance

Benchmarks

The numbers, with the asterisks attached

DaloyJS ships security on by default, so a fair comparison has to say so out loud. These charts come straight from the repo's own benchmark suite, and the caveats are part of the chart.

How DaloyJS measures up
Real numbers from the repo's own benchmark suite. Pick a metric, but keep the caveats below in mind, because none of these are a clean apples-to-apples comparison.

Transitive dependencies installed

Every package your install pulls in is attack surface someone has to trust. DaloyJS and Hono are the only two that bring zero.

What this means for you: Fewer packages to trust means fewer CVEs and no surprise postinstall scripts. Zero dependencies is zero supply-chain doors left open for an attacker.

Takeaway: DaloyJS installs 0 transitive dependencies, tied with Hono for the smallest supply-chain surface, while a secure NestJS app drags in 86.

Apple M3 Max · 16 cores · Node v25.7 · June 2026 · @daloyjs/core 1.0.0-beta.1 · source in bench/cross-framework

Why this is apples to oranges
These frameworks are not the same tool, so a head-to-head chart is closer to apples vs oranges than a fair race. Here is what these numbers do and don't prove, in plain terms.
  • Apples vs oranges, not apples to apples. These are different tools doing different amounts of work. On every request, DaloyJS validates the body against your Zod or Valibot schema and runs secure headers, a request ID, body-size limits, and request timeouts, all out of the box. The 'minimal' apps for the other frameworks do almost none of this, and even 'secure parity' rarely matches it one for one. So part of every DaloyJS number is security and validation you would otherwise have to build yourself.
  • Footprint methodology differs: DaloyJS is one zero-dependency package, while the others resolve transitive trees whose exact size depends on when the lockfile was generated.
  • Throughput is workload-shaped: with a comparable middleware stack on both sides, DaloyJS and Hono land within a handful of percent of each other (DaloyJS ~6% ahead on these GET routes). Real services are usually bound by database and I/O time, not framework dispatch, so these micro-numbers rarely predict production.
  • Different target runtimes: some frameworks (e.g. Elysia) are tuned for Bun but are measured here under their Node adapters for a fair single-runtime baseline.
  • Single machine, single moment: one Apple M3 Max, Node v25.7, June 2026, against @daloyjs/core 1.0.0-beta.1. Your hardware, runtime, and versions will move these numbers.

Support the project

If DaloyJS saves you time, you can buy me a coffee

DaloyJS is free and MIT-licensed. If the docs, posts, or the framework itself helped you ship something with a little less drama, coffee is a perfectly reasonable way to keep the work going.

Ready to ship, secure by default?

Scaffold a project in seconds with pnpm hardening when you choose pnpm, generated CI that blocks install scripts, pinned GitHub Actions, Dependabot, CODEOWNERS, and lockfile source verification. Then keep the contract as the app grows, the same app runs on Node, Bun, Deno, and Cloudflare Workers.

For developers and AI agents

DaloyJS is MCP-ready

The Model Context Protocol (MCP) is the open standard AI agents like Claude, Cursor, and VS Code use to call tools and read docs. DaloyJS supports it on both ends: your app can become an MCP server, and these docs already are one.

Turn your API into an MCP server

DaloyJS builds MCP servers from @daloyjs/core alone, no SDK required: Streamable HTTP transport, input-schema validation, and a production boot guard that refuses to ship an unauthenticated MCP endpoint by accident.

Build an MCP server →
ts
import { App, createMcpHandler, mcpRoutes } from "@daloyjs/core";

const mcp = createMcpHandler({
  serverInfo: { name: "inventory-mcp", version: "1.0.0" },
  tools: [/* your tools, with validated input schemas */],
});

const app = new App();
for (const route of mcpRoutes("/mcp", mcp)) {
  app.route(route); // your API is now an MCP server too
}

Read these docs over MCP

A public, read-only endpoint your AI coding agent can search and read without copy and paste. No API key needed.

Endpoint
Point any MCP-compatible client at this URL:
https://daloyjs.dev/mcp
  • search_docsKeyword search across every docs page, ranked by relevance.
  • get_docRead the full text of one page by its route or slug.
  • list_docsBrowse every available documentation page in one call.

Add it to your MCP client config

json
{
  "mcpServers": {
    "daloyjs-docs": {
      "url": "https://daloyjs.dev/mcp"
    }
  }
}

Using a stdio-only client? Bridge it with npx -y mcp-remote https://daloyjs.dev/mcp.