TypeBox + Fastify
Skill: fastify
Scope
- Applies to: Fastify v5+ with TypeBox schemas, type-safe route definitions, automatic OpenAPI generation, plugins, hooks, testing
- Does NOT cover: Database integration (see drizzle-orm)
Assumptions
- Fastify v5+
@fastify/type-provider-typeboxfor TypeBox type provider@sinclair/typeboxfor schema definitions- TypeScript v5+ with strict mode
Principles
- Use TypeBox schemas for route validation (params, query, body, response)
- Use
TypeBoxTypeProviderfor automatic type inference from schemas - Define response schemas for all status codes
- Use OpenAPI generation from schemas (via
@fastify/swagger) - Request types (
request.params,request.query,request.body) are inferred from schemas - Response validation happens automatically based on schema
Constraints
MUST
- Use
TypeBoxTypeProviderfor type safety:fastify.withTypeProvider<TypeBoxTypeProvider>() - Define response schemas for all status codes
- Use TypeBox
Type.*constructors for schema definitions
SHOULD
- Use
operationIdin route schemas for OpenAPI generation - Use
tagsfor route organization in OpenAPI docs - Define error response schemas for error cases
AVOID
- Manual type assertions (types inferred from schemas)
- Skipping response schema definitions
- Mixing TypeBox with other schema libraries in same route
Interactions
- Complements drizzle-orm for database integration
- Generates OpenAPI specs compatible with openapi-ts codegen
Patterns
Route Schema Pattern
import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync } from 'fastify'
const UserSchema = Type.Object({
id: Type.String(),
email: Type.String({ format: 'email' }),
name: Type.String(),
})
const userRoutes: FastifyPluginAsync = async fastify => {
fastify.get('/users/:id', {
schema: {
operationId: 'getUser',
params: Type.Object({ id: Type.String() }),
response: {
200: UserSchema,
404: Type.Object({ code: Type.String(), message: Type.String() }),
},
},
}, async (request, reply) => {
// request.params.id is typed
const { id } = request.params
return reply.send(user)
})
}
Schema Types
Type.String()
Type.Number()
Type.Boolean()
Type.Object({ id: Type.String() })
Type.Array(Type.String())
Type.Optional(Type.String())
Type.Union([Type.String(), Type.Number()])
See Route Schema Template for complete example.
Instance Configuration
Configure Fastify instance with TypeBox type provider, logger, and request settings:
import type { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import Fastify from 'fastify'
const fastify = Fastify({
logger: {
level: 'info',
transport: process.env.NODE_ENV === 'development' ? {
target: 'pino-pretty',
} : undefined,
},
trustProxy: true,
bodyLimit: 1048576, // 1MB
requestTimeout: 30000,
requestIdHeader: 'x-request-id',
requestIdLogLabel: 'reqId',
}).withTypeProvider<TypeBoxTypeProvider>()
See Instance Configuration for complete setup.
Plugin Development
Create reusable plugins with fastify-plugin for non-encapsulated behavior:
import type { FastifyPluginAsync } from 'fastify'
import fp from 'fastify-plugin'
const myPlugin: FastifyPluginAsync = async fastify => {
// Plugin logic
}
export default fp(myPlugin, {
name: 'my-plugin',
})
See Plugin Patterns and Plugin Template for examples.
Hooks (Request Lifecycle)
Use hooks to intercept requests, modify responses, or handle errors:
fastify.addHook('onRequest', async (request, reply) => {
// Add security headers, logging, etc.
})
fastify.addHook('onResponse', async (request, reply) => {
// Modify response, add headers, etc.
})
fastify.addHook('onError', async (request, reply, error) => {
// Handle errors
})
See Hooks Guide and Hook Plugin Template for patterns.
Testing with inject()
Test routes using Fastify's inject() method for blackbox testing:
const response = await fastify.inject({
method: 'GET',
url: '/users/123',
})
expect(response.statusCode).toBe(200)
const data = JSON.parse(response.body)
See Testing Patterns and Test Utils Template for setup.
Streaming Responses
Handle streaming responses (e.g., Server-Sent Events, text streams):
fastify.post('/stream', {
schema: {
response: {
200: Type.String({ description: 'Streaming response' }),
},
},
}, async (request, reply) => {
reply.header('Content-Type', 'text/event-stream')
reply.header('Cache-Control', 'no-cache')
return reply.send(stream)
})
Common Plugins
Rate Limiting
import rateLimit from '@fastify/rate-limit'
await fastify.register(rateLimit, {
max: 100,
timeWindow: 60000,
keyGenerator: request => request.ip,
})
CORS
import cors from '@fastify/cors'
await fastify.register(cors, {
origin: (origin, callback) => {
// Validate origin
callback(null, true)
},
credentials: false,
})
Error Handler
fastify.setErrorHandler((error, request, reply) => {
// Global error handling
reply.status(error.statusCode ?? 500).send({
code: 'ERROR',
message: error.message,
})
})
Graceful Shutdown
Handle process signals for graceful shutdown:
const shutdown = async (signal: string) => {
fastify.log.info({ signal }, 'Shutting down')
await fastify.close()
process.exit(0)
}
process.on('SIGTERM', () => shutdown('SIGTERM'))
process.on('SIGINT', () => shutdown('SIGINT'))
AutoLoad Pattern
Use @fastify/autoload for automatic plugin/route discovery:
import AutoLoad from '@fastify/autoload'
await fastify.register(AutoLoad, {
dir: path.join(__dirname, 'plugins'),
forceESM: true,
})
References
- OpenAPI Integration - OpenAPI generation patterns
- Plugin Patterns - Plugin development with fastify-plugin
- Hooks Guide - Request lifecycle hooks
- Testing Patterns - Testing with inject()
- Instance Configuration - Fastify instance setup
More from blockmatic/basilic
hey api codegen
|
36ai sdk v6 ui
|
32typescript-advanced-patterns
Advanced TypeScript patterns for type-safe, maintainable code using sophisticated type system features. Use when building type-safe APIs, implementing complex domain models, or leveraging TypeScript's advanced type capabilities.
28drizzle orm
|
27emilkowal-animations
Emil Kowalski's animation best practices for web interfaces. Use when writing, reviewing, or implementing animations in React, CSS, or Framer Motion. Triggers on tasks involving transitions, easing, gestures, toasts, drawers, or motion.
27vercel-react-best-practices
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
26