Limitations & roadmap
Limitations & roadmap
Section titled “Limitations & roadmap”This page is intentionally honest: what does not work well yet and what we are aiming for next. It is not a dated release plan—order and timing can change. For shipped changes, see the Changelog.
Current limitations
Section titled “Current limitations”| Area | What to expect |
|---|---|
| GraphQL schema stitching | Queries, mutations and — as of v3.4.0 — subscriptions all execute. Schema stitching is still not hardened; compose schemas at the gateway rather than relying on the plugin for it. |
| ORM integrations | Drizzle has first-class DI helpers (registerDrizzle, @InjectDB). Prisma and TypeORM are not yet at the same level of built-in, documented integration—you can still use them directly inside your services. All three provide native count/updateMany/deleteMany; a custom repository must override them itself (the base implementations now throw NotImplementedError rather than silently scanning the whole table). |
| Test coverage | Line coverage over src/ is ~57%, with the CI gate at 55% to prevent regressions. The thinnest remaining areas, measured: the cache and request-context middleware (~3%), the logging middleware and health plugin (~5%), the WebSocket plugin (~7%), and the OAuth and permission helpers with the RBAC decorators (~10–21%). Treat lightly covered paths with more caution than the core routing/validation surface. |
What shipped in v3.4.0
Section titled “What shipped in v3.4.0”- ✅ GraphQL subscriptions execute — the largest remaining gap. They were generated into the SDL and nothing more; there was no execution transport, so subscribing did nothing.
GraphQLPluginnow serves them over graphql-transport-ws (the subprotocol Apollo Client, urql, GraphiQL and thegraphql-wsclient speak) on Bun, Deno and Node, with aPubSubbuilt on the event bus, per-connection auth throughconnectionParams, and bounded backpressure. The protocol is the framework’s own, so CI runs it against the officialgraphql-wsclient rather than assuming interoperability. See GraphQL → Subscriptions. - ✅
app.listen(0)reports the port it got — it returned the requested port, so asking the OS for a free one left you with0. - ✅ A
WebSocketPlugingateway and the subscription endpoint coexist on Node — each was creating its own@hono/node-wsinstance, and every instance ends any upgrade it finds no waiter for, so the two destroyed each other’s connections.
What shipped in v3.3.0
Section titled “What shipped in v3.3.0”- ✅ The
@On('event')decorator — declarative listeners, registered withapp.include()and resolved through the DI container, so a listener injects the same services a controller can. Subscriptions attach atcompile()and detach atshutdown(), which matters on the process-wideglobalEvents: without it, every app built in a test suite answers the same event.new VeloceTS({ eventBus })takes a bus of your own. See Event Bus.
What shipped in v3.2.0
Section titled “What shipped in v3.2.0”- ✅ WebSockets on Node.js — the framework’s longest-standing limitation. Node upgrades now go through the optional
@hono/node-wspeer dependency; the decorators andWebSocketConnectionAPI are identical on Bun, Deno and Node. The plugin attaches inonStart(), so the app must be served withapp.listen(). All four CLI templates,websocketandfullstackincluded, now boot under Node in CI. See WebSockets. - ✅ The published package shrank 72% — 1.5 MB → 0.41 MB packed, by dropping JS sourcemaps and 351 KB of declaration maps that pointed at a
src/the package does not ship. - ✅ The declarations work under
node16/nodenext— the published types resolved only undermoduleResolution: bundlerbefore.
What shipped in v3.1.0
Section titled “What shipped in v3.1.0”- ✅ The CLI works on Node —
veloce devandveloce builddetect the runtime and accept--runtime auto|bun|node; the Node paths usetsxandtsc - ✅ Generated projects run on Node — they previously emitted a CORS config the framework rejects (so the app crashed on startup), extensionless imports Node’s ESM loader cannot resolve, and scripts that hardcoded
bun - ✅ Template smoke test in CI — every template is scaffolded, installed, type-checked, built and booted under Node on each run
Still Bun/Deno only: the websocket and fullstack templates, because WebSocketPlugin has no Node upgrade path yet. veloce new warns about this at scaffold time.
What shipped in v3.0.0
Section titled “What shipped in v3.0.0”- ✅ Guard enforcement — the three affected plugins now inject their guard during
install() - ✅ Signed session cookies —
SessionConfig.secretis required and the cookie is HMAC-signed; it previously carried the raw session id - ✅ Atomic refresh-token rotation — two concurrent refreshes with the same token no longer both succeed
- ✅ Request body limit —
bodyLimit, 1 MiB by default - ✅ Per-caller cache keys —
varyByHeaders/keyGeneratoron@Cache(), plus a compile-time warning when a per-user route is cached under a shared key - ✅ Node
listen()actually works — it usedrequire()inside the ESM bundle, so it always threw - ✅ Exception filters see validation and DI errors; class-level
@UseInterceptorruns; the DI container no longer reports false circular dependencies under concurrency - ✅ Distributed rate limiting —
RedisRateLimitStore - ✅ Typed context variables —
c.get('auth.user')is typed
What shipped in v2.0.0
Section titled “What shipped in v2.0.0”- ✅ Security — refresh tokens can no longer be replayed as access tokens;
RS256/384/512genuinely sign asymmetrically (they previously used the shared HMAC secret); rate limiting no longer trusts client-suppliedX-Forwarded-ForunlesstrustProxyis set - ✅ Node.js support actually works — the published 1.2.0 had four packaging bugs that broke it for Node consumers, including a bundled duplicate of Zod that silently broke
instanceofchecks against your own schemas - ✅ Performance — request dispatch substantially faster than v0.4.18; the package is 1.33 MB, down from 3.82 MB
- ✅ Typed functional API — handler arguments infer from the declared Zod schema bag
- ✅ Distributed token revocation —
RedisTokenBlacklistpropagates logout across replicas - ✅ Plugin lifecycle —
onStart/onStophooks - ✅ Cloudflare Workers —
app.getFetchHandler()is the supported deploy path - ✅ WebSocket hardening (Bun/Deno) — heartbeat, idle timeout, max message size
- ✅ CLI runs under plain Node — it previously required Bun
What shipped in v1.2.0
Section titled “What shipped in v1.2.0”All P0 and P1 roadmap items are now live:
- ✅ CLI scaffolding —
veloce generate module/controller/service/resolver/dto/middleware/plugin - ✅ Graceful shutdown —
app.onShutdown(), SIGTERM/SIGINT, configurable timeout - ✅ Exception filters —
@Catch(),app.useFilter(),FilterManager - ✅ Interceptors —
@UseInterceptor(),app.useInterceptor(),ExecutionContext - ✅ Streaming responses —
@SSE(),@Stream(contentType)onAsyncGeneratorhandlers - ✅ Event bus —
EventBus,globalEventssingleton - ✅ Extra decorators —
@Throttle,@ApiVersion,@ResponseHeader,@Redirect,@Deprecated - ✅ Test isolation —
isolate(),compileTestApp() - ✅ OpenAPI 3.1 —
jsonSchemaDialect,nullablenormalization
Planned updates (directional)
Section titled “Planned updates (directional)”Priorities the maintainers care about; not a promise of order or date.
- ORM choice — Make Drizzle, Prisma, and TypeORM practical, documented options so teams can pick an ORM without fighting the framework.
- GraphQL schema stitching — Subscriptions execute as of v3.4.0; composing schemas across services is the part that is still not hardened.
- Raise the coverage floor — The CI gate sits at 55% to block regressions; the goal is to lift it as the thin areas above get tested.
Now published: a reproducible benchmark suite comparing Veloce-TS against Hono, Express and Fastify (BENCHMARKS.md, bun run benchmark). Honest summary: Veloce-TS costs 2–11% over raw Hono — the price of the decorator layer, widest on a trivial /hello route and narrowest on Zod validation, where Zod dominates both sides — and is roughly 1.8× faster than Express 4 and 1.3–1.4× faster than Fastify 5 under Bun. Elysia and NestJS are not included yet.
Earlier editions claimed Veloce-TS beat raw Hono on two scenarios. Those came from single-pass measurements that flipped between runs; the harness now repeats each measurement and reports a median with its spread.
How to contribute or discuss
Section titled “How to contribute or discuss”- Shipped work: Changelog and the GitHub repository.
- Ideas and proposals: GitHub Discussions.