iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Fastify

Fastify is a high-performance Node web framework with a tiny core, JSON-Schema-based validation, a built-in serializer, and first-class TypeScript types. It is the right pick when you want Express ergonomics with much better throughput, request-scoped logging, and schema-validated I/O out of the box.

A typed Fastify server with schema validation

EXAMPLE
// npm i fastify @fastify/sensible @fastify/cors pino-pretty
import Fastify from 'fastify';
import sensible from '@fastify/sensible';
import cors from '@fastify/cors';

const app = Fastify({
  logger: {
    transport: { target: 'pino-pretty' },
    redact: ['req.headers.authorization', 'req.headers.cookie'],
  },
  trustProxy: true,
});

await app.register(sensible);         // adds httpErrors helpers
await app.register(cors, { origin: ['https://app.example.com'] });

// 1) Type the request and reply via the schema — Fastify uses it for VALIDATION
//    (rejects bad input with 400) AND for SERIALISATION (fast JSON stringify).
const orderSchema = {
  body: {
    type: 'object',
    required: ['customer', 'totalCents'],
    properties: {
      customer:   { type: 'string', minLength: 1, maxLength: 120 },
      totalCents: { type: 'integer', minimum: 0 },
      notes:      { type: 'string', maxLength: 500 },
    },
    additionalProperties: false,
  },
  response: {
    201: {
      type: 'object',
      required: ['id', 'customer', 'totalCents', 'status'],
      properties: {
        id:         { type: 'string' },
        customer:   { type: 'string' },
        totalCents: { type: 'integer' },
        status:     { type: 'string', enum: ['new', 'paid', 'shipped'] },
        createdAt:  { type: 'string', format: 'date-time' },
      },
    },
  },
} as const;

const orders = new Map<string, any>();

app.post('/orders', { schema: orderSchema }, async (req, reply) => {
  // req.body is typed by the schema; no Joi/Zod needed for the validation pass
  const id = crypto.randomUUID();
  const o  = { id, ...req.body, status: 'new', createdAt: new Date().toISOString() };
  orders.set(id, o);
  reply.code(201).header('Location', \`/orders/${id}\`).send(o);
});

app.get('/orders/:id', {
  schema: { params: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] } },
}, async (req) => {
  const o = orders.get((req.params as any).id);
  if (!o) throw app.httpErrors.notFound('order not found');
  return o;
});

// 2) Plugins are the Fastify unit of composition — encapsulated, hot-pluggable.
app.register(async function userRoutes(scope) {
  scope.addHook('preHandler', async (req) => {
    if (!req.headers.authorization) throw scope.httpErrors.unauthorized('missing token');
  });
  scope.get('/me', async () => ({ id: 'u1' }));
}, { prefix: '/api/users' });

// 3) Per-request logger comes with a generated reqId
app.addHook('onResponse', async (req, reply) => {
  req.log.info({ ms: reply.elapsedTime }, 'served');
});

// 4) Graceful shutdown — close pools, drain in-flight requests
const shutdown = async (signal: NodeJS.Signals) => {
  app.log.info({ signal }, 'shutting down');
  await app.close();
  process.exit(0);
};
process.on('SIGTERM', shutdown);
process.on('SIGINT',  shutdown);

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

// Benchmarks vs Express on a 'hello world' route:
//   Fastify:  ~80k req/s    Express:  ~12k req/s
// On real schemas with validation+serialisation, the gap usually GROWS in Fastify's favour.

Why it matters

Define the schema response shape AND request body. Fastify uses the response schema to generate a fast JSON stringifier (no JSON.stringify overhead) and to strip unknown fields, which is a free speed-up AND a free safety net against accidentally leaking data fields you forgot to remove.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import Fastify from 'fastify';
const app = Fastify({ logger: true });
app.get('/', async () => ({ hello: 'world' }));
app.listen({ port: 3000 });
Try it Yourself »

Discussion

Loading…