@fluojs/platform-fastify
v1.0.8
Published
Fastify-based HTTP adapter for the Fluo runtime.
Maintainers
Readme
@fluojs/platform-fastify
Fastify-backed HTTP adapter for the fluo runtime.
Table of Contents
- Installation
- When to Use
- Quick Start
- Common Patterns
- Performance
- Conformance Coverage
- Public API Overview
- Troubleshooting
- Related Packages
- Example Sources
Installation
npm install @fluojs/platform-fastify fastifyWhen to Use
Use this package when you need a high-performance HTTP adapter for your fluo application. Fastify is known for its low overhead and efficient request handling, making it the recommended choice for production fluo applications requiring high throughput and concurrency.
Quick Start
import { createFastifyAdapter } from '@fluojs/platform-fastify';
import { fluoFactory } from '@fluojs/runtime';
import { AppModule } from './app.module';
const app = await fluoFactory.create(AppModule, {
adapter: createFastifyAdapter({ port: 3000 }),
});
await app.listen();createFastifyAdapter() defaults to port 3000 and does not read process.env.PORT; invalid explicit numeric options such as port, maxBodySize, retryDelayMs, retryLimit, and shutdownTimeoutMs throw during adapter setup. maxBodySize and shutdownTimeoutMs are non-negative integer byte/time limits, so 0 is valid: maxBodySize: 0 allows only empty request bodies, and shutdownTimeoutMs: 0 asks Fastify to close on the next timer turn.
Common Patterns
Multipart and Raw Body
The Fastify adapter includes built-in support for multipart form-data and raw body parsing via internal Fastify plugins, exposed through the standard fluo request interface. When rawBody: true is enabled, FrameworkRequest.rawBody preserves the original request bytes for non-multipart requests so webhook signature verification and other byte-sensitive flows can replay the exact payload. When you construct the adapter directly, pass multipart limits as the second argument. bootstrapFastifyApplication(...) and runFastifyApplication(...) accept the same multipart settings under options.multipart.
Raw-body capture is skipped for multipart requests, including mixed-case Content-Type media values such as Multipart/Form-Data. When multipart.maxTotalSize is omitted, it defaults to maxBodySize so size limits stay portable across HTTP adapters.
const adapter = createFastifyAdapter(
{
port: 3000,
rawBody: true,
},
{
maxTotalSize: 10 * 1024 * 1024,
},
);Server-Backed Real-Time
Fastify provides a server-backed capability that allows @fluojs/websockets to attach directly to the underlying Node.js HTTP server.
@WebSocketGateway({ path: '/ws' })
export class MyGateway {}Streaming Responses
Fastify-backed response streams support the shared fluo stream contract used by SSE and other streaming writers. response.stream.waitForDrain() settles when the underlying response emits drain, close, or error, so writers do not hang when a client disconnects or the stream closes before backpressure clears.
CORS Configuration
CORS is handled via bootstrap options. fluo manages the underlying CORS logic rather than relying on a separate Fastify plugin.
// Simple origin string
await bootstrapFastifyApplication(AppModule, {
cors: 'https://my-frontend.com',
port: 3000,
});
// Fine-grained control
await bootstrapFastifyApplication(AppModule, {
cors: {
origin: ['https://a.com', 'https://b.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
},
port: 3000,
});
// Explicitly disabled
await bootstrapFastifyApplication(AppModule, {
cors: false,
port: 3000,
});Global Prefix
Configure a global routing prefix and exclude specific paths like health checks.
await bootstrapFastifyApplication(AppModule, {
globalPrefix: '/api',
globalPrefixExclude: ['/health'],
port: 3000,
});Logging
fluo uses its own logging system. The adapter creates the Fastify instance with its native logger disabled, and bootstrapFastifyApplication(...) / runFastifyApplication(...) select the framework console logger by default so startup and shutdown diagnostics stay consistent with the active runtime. Pass logger when a test harness or host application needs to capture those diagnostics through an injected ApplicationLogger instead of the default console logger.
Middleware
You can register runtime-level middleware that runs before the request reaches the handlers. Note that these are standard MiddlewareLike functions, not Fastify-specific plugins.
await bootstrapFastifyApplication(AppModule, {
middleware: [myCustomMiddleware],
port: 3000,
});Native Route Registration with Safe Fallback
When fluo route metadata can be translated directly, the adapter registers Fastify-native per-route handlers for explicit GET, POST, PUT, PATCH, DELETE, and HEAD routes instead of sending every request through a single wildcard route. For semantically safe unversioned routes, those native handlers hand a pre-matched descriptor and params to the shared fluo dispatcher so duplicate route matching is skipped without changing framework-owned guards, interceptors, observers, SSE, multipart, raw body, streaming, or error handling.
When multiple routes share the same method and normalized param shape (for example /:id and /:slug), use @All(...), depend on non-URI versioning, or arrive through duplicate-slash / trailing-slash variants, the adapter intentionally leaves those requests on the wildcard fallback path so Fastify registration cannot boot-fail or narrow fluo's matching semantics. If app middleware rewrites the framework request method or path after a native handoff was attached, the dispatcher ignores that stale handoff and rematches the rewritten request.
The adapter keeps a wildcard fallback route for unmatched paths and portability-sensitive cases, and enables Fastify trailing-slash / duplicate-slash normalization so native selection stays aligned with fluo's documented route path contract. CORS handling remains owned by fluo's shared middleware path rather than Fastify plugins, and unsupported methods such as OPTIONS continue through the fallback dispatcher path unless a fluo route explicitly owns them.
Performance
fluo's Fastify adapter significantly outperforms the raw Node.js adapter in high-concurrency scenarios.
| Adapter | Requests/sec | Avg Latency | | --- | ---: | ---: | | Raw Node.js Adapter | ~31,000 | 4.0ms | | Fastify Adapter | ~58,000 | 2.1ms |
Measured using wrk on a standard /health endpoint.
Conformance Coverage
packages/platform-fastify/src/adapter.test.ts is the package-local regression target for the documented Fastify adapter contract. It runs the shared createHttpAdapterPortabilityHarness(...) checks for malformed cookie preservation, JSON/text raw-body capture, byte-exact raw-body capture, multipart raw-body exclusion, multipart total-size defaults, SSE framing, response stream drain settlement, host and HTTPS startup logging, and shutdown signal listener cleanup.
The same file also covers Fastify-specific native route registration with wildcard fallback, duplicate shape route fallback, middleware/guard/interceptor/observer ordering, CORS ownership, global prefix behavior, malformed cookie preservation, response serialization parity, raw-body pre-parsing behavior, case-insensitive multipart detection, and multipart limit handling. Keep README example pointers aligned with that test file and the custom adapter book chapter when changing startup, routing, or adapter portability behavior.
Public API Overview
createFastifyAdapter(options, multipartOptions?): Recommended factory for the Fastify adapter. The optional second argument configures multipart limits such asmaxFileSize,maxFiles, andmaxTotalSizefor direct adapter construction.bootstrapFastifyApplication(module, options): advanced bootstrap without implicit listening.runFastifyApplication(module, options): Quick-start helper with lifecycle management. On timeout/failure it reports the condition through logging andprocess.exitCode, while leaving final process termination to the surrounding host.isFastifyMultipartTooLargeError(error): Detects multipart limit errors across Fastify error shapes.FastifyHttpApplicationAdapter: The core adapter implementation.- Option types:
FastifyAdapterOptions,BootstrapFastifyApplicationOptions,RunFastifyApplicationOptions,CorsInput,FastifyApplicationSignal.
Troubleshooting
- CORS Errors: Ensure you're using the
corsbootstrap option. Since Fastify's native CORS plugin is not registered, only the fluo-managed CORS logic applies. - Middleware Issues: The
middlewareoption accepts runtime-levelMiddlewareLike[]functions. These are not Fastify plugins and follow the standard middleware interface used across fluo adapters. - Logging: The native Fastify logger is disabled to prevent duplicate log streams.
runFastifyApplicationandbootstrapFastifyApplicationselect the framework console logger by default and acceptloggerfor hosts or tests that need an injectedApplicationLogger. - Global Prefix: Use
globalPrefixExcludeto prevent the prefix from being applied to internal routes or health check endpoints. - Malformed Cookies: Malformed cookie headers are preserved rather than failing the request.
Related Packages
@fluojs/runtime: Core framework runtime.@fluojs/platform-express: Alternative Express-based adapter.@fluojs/websockets: Real-time gateway support.
Example Sources
packages/platform-fastify/src/adapter.test.tsexamples/minimal/src/main.tsexamples/realworld-api/src/main.ts
