Skip to content
Back to skills

Fastify

ASecurity

Fastify is a high-performance Node.js web framework focused on developer experience and low overhead. It features JSON Schema validation, a powerful plugin system, lifecycle hooks, and automatic serialization for blazing-fast APIs.

  • 142 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added May 29, 2026
developmentjavascriptgojavabashnodetestingapidatabaseperformance

Works with

  • terminal
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned May 29, 2026

npx -y skills add TerminalSkills/skills --skill fastify --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Fastify?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Fastify
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-fastify/badge)](https://www.skillsdirectory.com/skills/terminalskills-fastify)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: fastify
description: |
  Fastify is a high-performance Node.js web framework focused on developer experience
  and low overhead. It features JSON Schema validation, a powerful plugin system,
  lifecycle hooks, and automatic serialization for blazing-fast APIs.
license: Apache-2.0
compatibility: 'node >= 18, npm or yarn or pnpm'
metadata:
  author: terminal-skills
  version: 1.0.0
  category: development
  tags:
    - node
    - javascript
    - api
    - rest
    - performance
    - plugins
---

# Fastify

Fastify is one of the fastest Node.js web frameworks. It validates requests via JSON Schema, serializes responses automatically, and organizes code through an encapsulated plugin system.

## Installation

```bash
# Create Fastify project
mkdir my-api && cd my-api
npm init -y
npm i fastify @fastify/autoload @fastify/sensible @fastify/cors @fastify/jwt
```

## Project Structure

```
# Recommended Fastify project layout
src/
├── app.js             # App factory
├── server.js          # Entry point
├── plugins/           # Shared plugins (db, auth)
│   ├── db.js
│   └── auth.js
├── routes/            # Route modules
│   ├── articles/
│   │   ├── index.js   # Route handler
│   │   └── schema.js  # JSON schemas
│   └── health.js
└── test/
    └── articles.test.js
```

## App Setup

```javascript
// src/app.js — application factory with autoload
import Fastify from 'fastify';
import autoload from '@fastify/autoload';
import sensible from '@fastify/sensible';
import cors from '@fastify/cors';
import { join } from 'node:path';

export function buildApp(opts = {}) {
  const app = Fastify({ logger: true, ...opts });

  app.register(sensible);
  app.register(cors, { origin: true });
  app.register(autoload, { dir: join(import.meta.dirname, 'plugins') });
  app.register(autoload, { dir: join(import.meta.dirname, 'routes'), options: { prefix: '/api' } });

  return app;
}
```

```javascript
// src/server.js — start the server
import { buildApp } from './app.js';

const app = buildApp();
app.listen({ port: 3000, host: '0.0.0.0' }, (err) => {
  if (err) { app.log.error(err); process.exit(1); }
});
```

## Routes with Schema Validation

```javascript
// src/routes/articles/schema.js — JSON Schema definitions
export const articleSchema = {
  type: 'object',
  properties: {
    id: { type: 'integer' },
    title: { type: 'string' },
    body: { type: 'string' },
    createdAt: { type: 'string', format: 'date-time' },
  },
};

export const createArticleSchema = {
  body: {
    type: 'object',
    required: ['title', 'body'],
    properties: {
      title: { type: 'string', maxLength: 200 },
      body: { type: 'string' },
    },
  },
  response: { 201: articleSchema },
};
```

```javascript
// src/routes/articles/index.js — article CRUD routes
import { createArticleSchema } from './schema.js';

export default async function articleRoutes(fastify) {
  fastify.get('/', async (request) => {
    const { page = 1, limit = 20 } = request.query;
    const offset = (page - 1) * limit;
    const { rows } = await fastify.db.query(
      'SELECT * FROM articles ORDER BY created_at DESC LIMIT $1 OFFSET $2',
      [limit, offset]
    );
    return rows;
  });

  fastify.get('/:id', async (request, reply) => {
    const { rows } = await fastify.db.query('SELECT * FROM articles WHERE id = $1', [request.params.id]);
    if (!rows[0]) return reply.notFound();
    return rows[0];
  });

  fastify.post('/', { schema: createArticleSchema, preHandler: [fastify.authenticate] }, async (request, reply) => {
    const { title, body } = request.body;
    const { rows } = await fastify.db.query(
      'INSERT INTO articles (title, body) VALUES ($1, $2) RETURNING *',
      [title, body]
    );
    return reply.code(201).send(rows[0]);
  });
}
```

## Plugins

```javascript
// src/plugins/db.js — database plugin with pg
import fp from 'fastify-plugin';
import pg from 'pg';

export default fp(async function dbPlugin(fastify) {
  const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
  fastify.decorate('db', pool);
  fastify.addHook('onClose', () => pool.end());
});
```

```javascript
// src/plugins/auth.js — JWT auth plugin
import fp from 'fastify-plugin';
import jwt from '@fastify/jwt';

export default fp(async function authPlugin(fastify) {
  fastify.register(jwt, { secret: process.env.JWT_SECRET || 'dev-secret' });

  fastify.decorate('authenticate', async function (request, reply) {
    try {
      await request.jwtVerify();
    } catch (err) {
      reply.unauthorized();
    }
  });
});
```

## Hooks

```javascript
// src/app.js — lifecycle hooks example (add inside buildApp)
app.addHook('onRequest', async (request) => {
  request.startTime = process.hrtime.bigint();
});

app.addHook('onResponse', async (request, reply) => {
  const duration = Number(process.hrtime.bigint() - request.startTime) / 1e6;
  request.log.info({ duration: `${duration.toFixed(2)}ms`, status: reply.statusCode }, 'request completed');
});
```

## Error Handling

```javascript
// src/app.js — custom error handler (add inside buildApp)
app.setErrorHandler((error, request, reply) => {
  request.log.error(error);
  const status = error.statusCode || 500;
  reply.code(status).send({
    error: error.name,
    message: status === 500 ? 'Internal Server Error' : error.message,
  });
});
```

## Testing

```javascript
// src/test/articles.test.js — testing with built-in inject
import { test } from 'node:test';
import assert from 'node:assert';
import { buildApp } from '../app.js';

test('GET /api/articles returns 200', async () => {
  const app = buildApp({ logger: false });
  const response = await app.inject({ method: 'GET', url: '/api/articles' });
  assert.strictEqual(response.statusCode, 200);
  await app.close();
});
```

## Key Patterns

- Use `fastify-plugin` (`fp`) for plugins that should share the same encapsulation context
- Use JSON Schema for validation — it also generates automatic serialization for speed
- Use `@fastify/autoload` to auto-register plugins and routes from directories
- Decorate the fastify instance (`fastify.decorate`) for shared services (db, cache)
- Use `@fastify/sensible` for `.notFound()`, `.unauthorized()`, etc. helpers
- Fastify is async-first: return values from handlers instead of calling `reply.send()`

Files in this skill

  • SKILL.md6.3 KB
  • _scores.json1.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.