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
  • 4 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…