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 API | Fastify 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.authContext | request.authContext |
req.originalUrl | request.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.
Related protocols
- 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/resare Fastify request/reply objects. Replacetrpc.middlewareswith nativehooksorplugins. 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).