Skip to content

Contract-first TypeScript REST APIs with secure defaults, built for AI-assisted teams

DaloyJS ships secure defaults, refuses to start in production on the misconfigurations it knows about, and runs with zero runtime dependencies and a hardened, provenance-signed publish pipeline. No framework makes an app fully secure or stops every supply-chain attack, so the docs say what is on by default, what you turn on, and the risks that remain.

$ pnpm create daloy@latest my-api
  • 3,000+ framework tests passing
  • ≥90% line/function and ≥92% branch coverage gates
  • 0 runtime dependencies
  • Node 24 LTS, Node 26+, Bun, Deno, Cloudflare
  • MIT licensed
ᜇᜎᜓᜌ᜔ Daloy means flow in Tagalog (pronounced da-loy).AboutThe nameBookstore tutorial

Security & Supply Chain

Security defaults: the defense layer for AI-generated code

When AI models generate code, developer typing speed is not the bottleneck: runtime safety and supply-chain integrity are. DaloyJS enforces guardrails at the runtime layer: request body limits, timeouts, prototype-pollution protection, 5xx detail redactions, and boot-time misconfiguration refusals, with zero transitive dependencies to exploit.

Secure runtime defaults

Unlike frameworks that leave basic protections to plugins or manual error routing, the DaloyJS core starts with guardrails on: body limits, request timeouts, prototype-pollution-safe JSON, proper 405 Method Not Allowed responses, and 5xx detail redaction that fails closed (on everywhere except an explicit development or test environment). In production it refuses to boot on the misconfigurations it knows about, such as weak session secrets or session cookies without CSRF.
Body limits (1 MiB default)Request timeoutsPrototype pollution defenseRFC 9457 problem+jsonStrict schema validationBoot misconfiguration guards

Zero runtime dependencies

Installing @daloyjs/core adds exactly zero transitive packages. No postinstall scripts to audit and no surprise CVEs from dependencies you never chose. The framework adds no dependency tree of its own; your app's other dependencies are still yours to vet.
0transitive packages in @daloyjs/core

Supply-chain-hardened scaffolds

Pick pnpm in create-daloy and pnpm-workspace.yaml is already hardened: ignoreScripts blocks install-script payloads (not code that runs on import), a 24-hour minimumReleaseAge waits out freshly published bad versions that get caught in time, and verifyStoreIntegrity 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.
ignoreScripts24h minimumReleaseAgeverifyStoreIntegrityPinned SHA Actionsdaloy doctor audit

AI-native scaffolding

Every project scaffolded by create-daloy includes an AGENTS.md and context skills, and these docs are readable over MCP. Coding agents that read AGENTS.md pick up your framework's conventions, routing rules, and security primitives without a prompt-engineering ritual.
AGENTS.md includedContext skillsReadable over MCP

Streaming & observability

Backpressure-safe SSE and NDJSON helpers, plus an OpenTelemetry tracing hook that emits HTTP server spans with semantic-convention attributes.
Backpressure-safe SSENDJSON streamingOTel HTTP server spans

Runtime-portable

The core only sees Request → Response. Adapters live at the edge: Node, Bun, Deno, Cloudflare Workers, Vercel, Fastly Compute, and AWS Lambda: same app, same tests.
Node 24+BunDenoCloudflare WorkersVercelAWS Lambda

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 validationOpenAPI 3.1 specHey API typed clientBuilt-in contract tests

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.
pnpm genZero configEnd-to-end typed fetch SDK

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.
Edge sessionsWebSocket rate limitsStructured logsGraceful shutdown

Benchmarks & Performance

The numbers, with the asterisks attached

When AI agents loop tools and stream high-concurrency requests, throughput and cold-start latency become critical. DaloyJS ships security checks on by default, and these benchmarks measure performance with every guard active.

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 means the framework adds no supply-chain doors of its own; the rest of your dependency tree is still yours to vet.

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 v26.4.0 · October 2026 · @daloyjs/core 1.5.4 · 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 comes out ~27% ahead of Hono on these GET routes and ~58% ahead on the POST body route, and DaloyJS is additionally Zod-validating that body. 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 v26.4.0, October 2026, against @daloyjs/core 1.5.4, with other background load on the machine (the two frameworks were measured back to back, so the comparison holds better than the absolute numbers). Your hardware, runtime, and versions will move these numbers.

Machine-Native: For AI Agents and Tools

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 start when an MCP endpoint has no auth hook in its chain. It checks that the hook is there and, in production, that it ran on each request, not that it rejects anyone, so test your auth too.

Build an MCP server →
ts
import { App, bearerAuth, 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();
app.use(bearerAuth({ validate: checkToken })); // no auth hook: production refuses to boot
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.

Blast-Radius Boundaries

Contracts as safety enclosures, not vanity syntax

In an AI-first workflow, contracts are not an aesthetic luxury for humans: they are the machine-enforced boundary that prevents hallucinated data structures from leaking between components. One route contract strictly validates requests, bounds response payloads, and emits the live OpenAPI 3.1 spec and typed client.

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
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 });

// requestId() and secureHeaders() are already auto-applied by new App();
// these explicit calls only customize (and replace) the defaults.
app.use(requestId());
app.use(secureHeaders());
app.use(rateLimit({ windowMs: 60_000, max: 120 })); // per client IP by default; behind a proxy, set behindProxy or keyGenerator

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 →

Ecosystem Tradeoffs

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: pnpm defaults + zero-runtime-dep core

Portable supply-chain hardening for the apps you build

What DaloyJS gives you

Hardened pnpm install settings, source-verified lockfiles, SBOM + npm provenance

You wantToday: Hono

Serverless / edge fit

What DaloyJS gives you

Web-standard core, multi-runtime adapters

You wantToday: Fastify

Mature Node ops & docs

What DaloyJS gives you

Encapsulated plugins, structured logs, graceful shutdown

You wantToday: Elysia

Modern TS-first DX, Bun OK

What DaloyJS gives you

End-to-end typed handlers, typed context, typed client

You wantToday: FastAPI

Best OpenAPI ergonomics

What DaloyJS gives you

Built-in OpenAPI 3.1 from one route definition

You wantToday: Hey API

Best typed client codegen

What DaloyJS gives you

pnpm gen → fully typed fetch SDK

Ready to ship with secure defaults?

Scaffold a project in seconds with install hardening for your package manager, 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.

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.