package.json for Hono 4.13.1 contains a devDependencies block and no dependencies field at all. That is the single most consequential technology decision in the repo: everything a request touches at runtime is code in src/, and everything in devDependencies exists only to build, test, and lint that code.
The practical payoffs, each verifiable in the tree:
- Install and cold-start cost are bounded.
npm install honobrings in exactly one package. The CI even enforces this direction:perf-measures/bundle-check/fails PRs that regress the minified bundle size ofdist/index.js. - Multi-runtime support gets easier. No transitive dependency can smuggle in a
node:API that breaks Workers or Deno. The only platform surface Hono relies on is Web Standards (see Web Standards as the platform). - Supply-chain exposure is limited to build time.
What is vendored or reimplemented instead
Capabilities that most frameworks import, implemented in-repo:
| Capability | Where it lives | Typical external equivalent |
|---|---|---|
| Routing (5 implementations) | src/router/ |
find-my-way, path-to-regexp |
| Middleware composition | src/compose.ts (based on the koa-compose algorithm, reimplemented) |
koa-compose |
| JSX runtime, server and DOM | src/jsx/ |
React, Preact |
| Request validation core | src/validator/ |
framework plugins |
| JWT sign/verify (HMAC, RSA, ECDSA via WebCrypto) | src/utils/jwt/ |
jsonwebtoken, jose |
| Cookie parse/serialize (incl. signed cookies) | src/utils/cookie.ts, src/helper/cookie/ |
cookie |
| HTML escaping and streaming templates | src/utils/html.ts, src/helper/html/ |
template libraries |
| Typed RPC client | src/client/ |
codegen tools (tRPC-style, no codegen here) |
| Body parsing (multipart, urlencoded, with dot-notation) | src/utils/body.ts |
formidable, busboy |
| 26 middleware (cors, etag, jwt, secure-headers, compress, ...) | src/middleware/ |
framework plugin ecosystems |
The one acknowledged inspiration that is code-level: src/compose.ts documents itself as "based on koa-compose package", and build/build.ts credits the build script it was adapted from. Attribution instead of dependency.
The dev toolchain, briefly
Every entry in devDependencies maps to a visible role:
- Build and publish:
esbuilddriven by a Bun script,publintas postbuild check,npfor releases,wrangleronly to run workerd tests -- covered in Build and release pipeline. - Test:
vitest+@vitest/coverage-v8,mswfor network mocking,jsdomfor the client-side JSX tests,wsfor WebSocket tests -- covered in The test matrix. - Types:
typescriptplus@typescript/native-preview(tsgo), whose type-check time is benchmarked in CI -- covered in TypeScript as a feature. - Style:
eslintwith the project's own shared@hono/eslint-config,prettier,editorconfig-checker. zodappears in devDependencies solely because validator tests and type-level tests use it as a realistic schema library; the shipped validator (src/validator/) does not import it.
Where third-party integrations do exist -- Zod validators, GraphQL, Sentry -- they live in the separate honojs/middleware repository as @hono/* packages, keeping this package's zero-dependency invariant intact (policy stated in docs/CONTRIBUTING.md).