Skip to Content
HeronJS v4 is now available.
4.0.0HTTPFastify Configuration

Fastify Configuration

The package remains @heronjs/express, and its HTTP engine is Fastify 5. The HTTP integration introduces breaking changes to request, reply, and middleware APIs. Module declarations, controllers, routes, DI, GraphQL schemas, tRPC procedures, and the shared-port architecture remain.

FastifyAdapter and FastifyServer are the canonical names. ExpressAdapter and ExpressServer are deprecated aliases to those implementations. Request and response objects are native Fastify objects; aliases do not adapt old middleware.

Request and reply

HttpRequest and HttpResponse represent FastifyRequest and FastifyReply. @Request(), @Response(), @Body(), @Params(), @Queries(), @Headers(), @Cookies(), and @Principal() remain available. @Header(name) selects one header. Route status/header metadata remains supported.

Express APIFastify API
res.status(code).send(body)reply.code(code).send(body)
res.set(name, value)reply.header(name, value)
req.get(name)request.headers[name.toLowerCase()]
res.locals.authContextrequest.authContext
req.originalUrlrequest.raw.url
next(error)throw the error from an async hook/handler

When a controller sends through an injected reply, HeronJS avoids sending a second response. HeronJS HTTP requests expose executionSignal for work cancelled by disconnect or application shutdown. Ordinary controller results support values, Promises, and Observables; unary operations send only the first emission.

Hooks, plugins, and parsers

Configure native Fastify options through FastifyHttpOptions:

import type {FastifyHttpOptions} from '@heronjs/express'; const options: FastifyHttpOptions = { fastify: {bodyLimit: 1024 * 1024, trustProxy: false}, hooks(instance) { instance.addHook('preHandler', async (request, reply) => { reply.header('x-request-id', request.id); }); }, plugins: [ async instance => { instance.addHook('onClose', async () => { await releaseApplicationResource(); }); }, ], cors: {origin: 'https://example.test'}, session: {secret: sessionSecret, cookie: {secure: true}}, }; await app.listen({port: 3000, options});

Read and validate sessionSecret during application configuration. The hooks callback registers hooks through the typed native Fastify instance; replace the former object keyed by hook names with instance.addHook(...) calls. Native hooks use Fastify callback or async conventions. HeronJS Interceptors accept request/reply functions returning values, Promises, or Observables. Replace Express parsers with contentTypeParsers or Fastify plugins. JSON, form parsing, cookies, CORS, and Helmet use Fastify-compatible implementations; sessions are enabled when configured. There is no Express middleware bridge.

Default proxy trust is false; configure trusted proxies explicitly. The default body limit remains 1 MiB, unless HTTP_BODY_LIMIT_SIZE or fastify.bodyLimit overrides it. Query parsing retains depth 3 and parameter limit 100. Routes remain case-insensitive and accept trailing slashes. The default port remains 3000; the default HTTP bind address is 0.0.0.0. Rendering remains unsupported.

  • GraphQL uses graphql-http/lib/use/fastify, preserving its schema engine and resolver decorators. GraphQL extension disposal cancels its active handlers.
  • tRPC uses @trpc/server/adapters/fastify; TRPCContext.req/res are Fastify request/reply objects. Replace trpc.middlewares with native hooks or plugins. Express middleware configuration is rejected at startup.
  • MCP retains exact raw HTTP mounts, SDK authentication/Host/Origin checks, and SDK body handling. WebSocket upgrades remain attached to the same Node server.
  • ACP supports separate HTTP agent endpoints and explicit stdio selection; EBS retains its transports. HTTP remains the application default; { runtime: { transport: 'stdio' } } explicitly selects stdio.

Extensions queue Fastify plugins through the shared FastifyHost.register capability. Registration returns void; only core awaits readiness after all protocol routes have been registered. Core coordinates one server’s startup and shutdown, releases protocol streams/upgraded sockets, and runs Fastify close hooks without closing the Node server twice.

HTTP shutdown aborts framework-owned request execution and forces remaining HTTP connections closed after shutdownTimeout (default 5000 ms). Native plugins remain responsible for completing their own lifecycle hooks.


Based on 4.0.0 release source  (4.0.0).

Last updated on