Overview
Start a NestJS application with Fastify adapter for higher performance. Includes Swagger, versioning, CORS, Helmet, and request logging.
Features
- Fastify adapter (higher performance)
- Swagger API documentation
- API versioning support
- Class-based modular setup
- Request/response logging
Installation
npx hanma add nest-fastify-server --framework nest
Dependencies
@nestjs/core, @nestjs/common, @nestjs/platform-fastify, @nestjs/swagger, @fastify/helmet
Code
import { ConfigService } from "@nestjs/config";
import { NestFactory } from "@nestjs/core";
import {
DynamicModule,
ForwardReference,
Type,
VersioningType,
Logger,
ValidationPipe,
} from "@nestjs/common";
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
import helmet from "@fastify/helmet";
import {
FastifyAdapter,
NestFastifyApplication,
} from "@nestjs/platform-fastify";
import type { ServerOptions } from "./server.interface";
type ModuleType = Type<any> | DynamicModule | ForwardReference;
export class HttpServer {
private static logger = new Logger("HTTP");
private static app: NestFastifyApplication;
/**
* Bootstrap and start the NestJS application
*/
static async create(module: ModuleType, options: ServerOptions = {}) {
const app = await NestFactory.create<NestFastifyApplication>(
module,
new FastifyAdapter(),
{
logger: ["log", "error", "warn", "debug", "verbose"],
}
);
this.app = app;
const config = app.get(ConfigService);
const isDev = config.get("NODE_ENV") !== "production";
// Apply defaults
const opts: Required<ServerOptions> = {
port: options.port ?? config.get<number>("PORT", 3000),
enableVersioning: options.enableVersioning ?? false,
defaultVersion: options.defaultVersion ?? "1",
enableApiDocumentation: options.enableApiDocumentation ?? isDev,
swaggerPath: options.swaggerPath ?? "api/docs",
enableServerLogs: options.enableServerLogs ?? true,
globalPrefix: options.globalPrefix ?? "api",
};
// Setup all middleware and configurations
this.setupGlobalPrefix(opts);
this.setupVersioning(opts);
this.setupCors(config);
await this.setupHelmet();
this.setupValidation();
this.setupSwagger(config, opts);
this.setupRequestLogging(opts);
this.setupGracefulShutdown();
// Start server
await app.listen(opts.port, "0.0.0.0");
this.logger.log(`Server running on: ${await app.getUrl()}`);
if (opts.enableApiDocumentation) {
this.logger.log(`API docs: ${await app.getUrl()}/${opts.swaggerPath}`);
}
return app;
}
private static setupGlobalPrefix(opts: Required<ServerOptions>) {
this.app.setGlobalPrefix(opts.globalPrefix);
}
private static setupVersioning(opts: Required<ServerOptions>) {
if (!opts.enableVersioning) return;
this.app.enableVersioning({
type: VersioningType.URI,
prefix: "v",
defaultVersion: opts.defaultVersion,
});
this.logger.log(`API versioning enabled (default: v${opts.defaultVersion})`);
}
private static setupCors(config: ConfigService) {
const allowedOrigins = config
.get<string>("CORS_ORIGINS", "*")
.split(",")
.map((origin) => origin.trim())
.filter(Boolean);
const allowedMethods = config
.get<string>("CORS_METHODS", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
.split(",")
.filter(Boolean);
this.app.enableCors({
origin: (origin, callback) => {
// Allow requests with no origin (like mobile apps or curl)
if (!origin || allowedOrigins.includes("*") || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
this.logger.warn(`CORS blocked: ${origin}`);
callback(new Error("Not allowed by CORS"), false);
}
},
methods: allowedMethods,
credentials: true,
});
}
private static async setupHelmet() {
await this.app.register(helmet, {
contentSecurityPolicy: process.env.NODE_ENV === "production",
});
}
private static setupValidation() {
this.app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
transformOptions: {
enableImplicitConversion: true,
},
})
);
}
private static setupSwagger(config: ConfigService, opts: Required<ServerOptions>) {
if (!opts.enableApiDocumentation) return;
const appName = process.env.npm_package_name || config.get<string>("APP_NAME", "NestJS API");
const appVersion = process.env.npm_package_version || config.get<string>("APP_VERSION", "1.0.0");
const appDescription = process.env.npm_package_description || config.get<string>("APP_DESCRIPTION", "API documentation");
const documentConfig = new DocumentBuilder()
.setTitle(appName)
.setDescription(appDescription)
.setVersion(appVersion)
.addBearerAuth()
.addTag("API")
.build();
const document = SwaggerModule.createDocument(this.app, documentConfig);
SwaggerModule.setup(opts.swaggerPath, this.app, document, {
swaggerOptions: {
persistAuthorization: true,
docExpansion: "none",
},
});
}
private static setupRequestLogging(opts: Required<ServerOptions>) {
if (!opts.enableServerLogs) return;
const instance = this.app.getHttpAdapter().getInstance();
// Track request start time
instance.addHook("onRequest", (req: any, _res: any, done: () => void) => {
req.startTime = Date.now();
done();
});
// Log response
instance.addHook("onResponse", (req: any, res: any, done: () => void) => {
const duration = Date.now() - req.startTime;
const { method, url } = req;
const statusCode = res.statusCode;
const logFn =
statusCode >= 500
? this.logger.error.bind(this.logger)
: statusCode >= 400
? this.logger.warn.bind(this.logger)
: this.logger.log.bind(this.logger);
logFn(`${method} ${url} ${statusCode} - ${duration}ms`);
done();
});
}
private static setupGracefulShutdown() {
this.app.enableShutdownHooks();
process.on("SIGTERM", async () => {
this.logger.log("SIGTERM signal received, closing gracefully...");
await this.app.close();
});
process.on("SIGINT", async () => {
this.logger.log("SIGINT signal received, closing gracefully...");
await this.app.close();
});
}
/**
* Get the application instance
*/
static getApp() {
return this.app;
}
}
/* USAGE in main.ts:
import { HttpServer } from "./server.setup";
import { AppModule } from "./app.module";
HttpServer.create(AppModule, {
enableVersioning: false,
enableApiDocumentation: true,
enableServerLogs: true,
}).catch((err) => {
console.error("Failed to start application:", err);
process.exit(1);
});
*/
Usage
HttpServer.create(AppModule, {\n enableVersioning: true,\n enableApiDocumentation: true,\n});
Dependencies
@nestjs/core@nestjs/common@nestjs/platform-fastify@nestjs/swagger@fastify/helmet
Frequently Asked Questions
How do I install NestJS Fastify Server?
Run the following command:
npx hanma add nest-fastify-server --framework nestWhat dependencies are required?
This snippet requires: @nestjs/core, @nestjs/common, @nestjs/platform-fastify, @nestjs/swagger, @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/main.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.