Fastify Core Knowledge

SkillAI & models

Fastify high-performance Node.js framework. Covers routing, plugins, validation, and serialization. Use when building fast Node.js APIs.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Fastify Core Knowledge skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/backend-frameworks/fastify/SKILL.md and read by ahel’s review.

Full Reference: See advanced.md for WebSocket authentication, room management, heartbeat patterns, message validation, and Redis scaling.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: fastify for comprehensive documentation.

Basic Setup

import Fastify from 'fastify';
import cors from '@fastify/cors';

const app = Fastify({ logger: true });

await app.register(cors);
await app.register(userRoutes, { prefix: '/api/users' });

app.listen({ port: 3000, host: '0.0.0.0' });

Route with Schema Validation

import { FastifyPluginAsync } from 'fastify';
import { Type, Static } from '@sinclair/typebox';

const UserSchema = Type.Object({
  name: Type.String(),
  email: Type.String({ format: 'email' }),
});

type User = Static<typeof UserSchema>;

const routes: FastifyPluginAsync = async (app) => {
  app.post<{ Body: User }>('/', {
    schema: {
      body: UserSchema,
      response: { 201: UserSchema }
    }
  }, async (request, reply) => {
    const user = await db.users.create(request.body);
    reply.status(201).send(user);
  });
};

Plugins

import fp from 'fastify-plugin';

// Custom plugin with fastify-plugin
export default fp(async (app) => {
  app.decorate('db', db);
  app.addHook('onRequest', async (request) => {
    request.startTime = Date.now();
  });
});

app.register(myPlugin);

Error Handling

import { FastifyError, FastifyReply, FastifyRequest } from 'fastify';

export class AppError extends Error {
  constructor(public statusCode: number, message: string) {
    super(message);
  }
}

app.setErrorHandler((error: FastifyError, request, reply) => {
  request.log.error({ err: error }, 'Request error');

  if (error.validation) {
    return reply.status(400).send({ error: 'Validation failed', details: error.validation });
  }

  return reply.status(error.statusCode || 500).send({ error: error.message });
});

Health Checks

app.get('/health', async () => ({ status: 'healthy' }));

app.get('/ready', async (request, reply) => {
  try {
    await app.pg.query('SELECT 1');
    return { status: 'ready', database: 'connected' };
  } catch (error) {
    reply.status(503);
    return { status: 'not ready' };
  }
});

Testing

import { test } from 'vitest';
import { buildApp } from '../src/app';

test('GET /api/users returns users', async () => {
  const app = await buildApp();

  const response = await app.inject({
    method: 'GET',
    url: '/api/users',
  });

  expect(response.statusCode).toBe(200);
  await app.close();
});

WebSocket Setup

import websocket from '@fastify/websocket';

await app.register(websocket);

app.get('/ws', { websocket: true }, (socket, req) => {
  socket.on('message', (data) => {
    const message = JSON.parse(data.toString());
    handleMessage(socket, message);
  });
});

When NOT to Use This Skill

  • Enterprise Architecture - Use NestJS for DI and modular design
  • Simple CRUD APIs - Use Express if performance is not critical
  • Edge Runtimes - Use Hono for Cloudflare Workers
  • Deno Projects - Use Oak or Fresh instead

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
Not using schema validationLoses performance advantageDefine schemas for routes
Missing fastify-plugin wrapperEncapsulation issuesUse fp() for shared plugins
Using app.listen() in testsSlow, port conflictsUse app.inject()
Ignoring response schemaSlower serializationDefine response schemas

Quick Troubleshooting

IssueLikely CauseSolution
"Cannot call reply.send twice"Multiple sendsReturn after first reply.send()
Plugin not accessibleMissing fastify-pluginWrap with fp()
Schema not workingNot registeredAdd schema: {} to route options
Type errors with schemasProvider missingUse withTypeProvider<TypeBoxTypeProvider>()

Production Checklist

  • TypeBox schema validation
  • Helmet security headers
  • Rate limiting configured
  • Structured logging (Pino)
  • Request ID tracing
  • Custom error handler
  • Health/readiness endpoints
  • Graceful shutdown
  • Database connection pooling

Monitoring Metrics

MetricTarget
Response time (p99)< 50ms
Error rate (5xx)< 0.1%
Request throughput> 10k/s

Reference Documentation

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
fastify
Source
github.com/claude-dev-suite/claude-dev-suite