Overview

Start a Fastify server with proper production configuration. Includes health checks, CORS, Helmet, and graceful shutdown.

Features

  • Graceful shutdown on SIGTERM/SIGINT
  • CORS and Helmet pre-configured
  • Health, ready, and live endpoints for k8s
  • Environment-based configuration
  • Pino structured logging

Installation

npx hanma add fastify-server --framework fastify

Dependencies

fastify, @fastify/cors, @fastify/helmet

Code

import Fastify, { FastifyInstance } from "fastify";
import cors from "@fastify/cors";
import helmet from "@fastify/helmet";

export interface ServerOptions {
  port?: number;
  host?: string;
  corsOrigins?: string[];
}

const getEnvConfig = () => ({
  port: parseInt(process.env.PORT ?? "3000", 10),
  host: process.env.HOST ?? "0.0.0.0",
  corsOrigins: (process.env.CORS_ORIGINS ?? "")
    .split(",")
    .map((o) => o.trim())
    .filter((o) => o.length > 0),
});

export async function createServer(options?: ServerOptions): Promise<FastifyInstance> {
  const config = { ...getEnvConfig(), ...options };
  
  const app = Fastify({
    logger: {
      level: process.env.LOG_LEVEL ?? "info",
      transport:
        process.env.NODE_ENV === "development"
          ? { target: "pino-pretty", options: { colorize: true } }
          : undefined,
    },
    requestIdHeader: "x-request-id",
    requestIdLogLabel: "requestId",
    disableRequestLogging: false,
  });

  // Security headers
  await app.register(helmet, {
    contentSecurityPolicy: process.env.NODE_ENV === "production",
  });

  // CORS
  await app.register(cors, {
    origin: config.corsOrigins.length > 0 ? config.corsOrigins : true,
    credentials: true,
  });

  // Health check endpoints
  app.get("/health", async () => ({
    status: "healthy",
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memoryUsage: process.memoryUsage(),
  }));

  app.get("/ready", async () => ({
    status: "ready",
    timestamp: new Date().toISOString(),
  }));

  app.get("/live", async () => ({
    status: "live",
    timestamp: new Date().toISOString(),
  }));

  return app;
}

export async function startServer(app: FastifyInstance, options?: ServerOptions): Promise<void> {
  const config = { ...getEnvConfig(), ...options };

  // Graceful shutdown
  const shutdown = async (signal: string) => {
    app.log.info(`Received ${signal}, shutting down gracefully...`);
    try {
      await app.close();
      app.log.info("Server closed successfully");
      process.exit(0);
    } catch (err) {
      app.log.error(err, "Error during shutdown");
      process.exit(1);
    }
  };

  process.on("SIGTERM", () => shutdown("SIGTERM"));
  process.on("SIGINT", () => shutdown("SIGINT"));

  try {
    await app.listen({ port: config.port, host: config.host });
    app.log.info(`Server listening on http://${config.host}:${config.port}`);
  } catch (err) {
    app.log.error(err);
    process.exit(1);
  }
}

// Usage example:
// const app = await createServer();
// await startServer(app);

Usage

import { createServer, startServer } from './server';

const app = await createServer();
await startServer(app);

Dependencies

Frequently Asked Questions

How do I install Fastify Server?
Run the following command: npx hanma add fastify-server --framework fastify
What dependencies are required?
This snippet requires: fastify, @fastify/cors, @fastify/helmet. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to src/server.ts.
Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.