A comprehensive sample Node-Boot application using Fastify framework that demonstrates best practices for building scalable TypeScript applications with dependency injection, validation, persistence, and more.
- Node.js (LTS version recommended)
- pnpm (package manager)
- SQLite (for local development)
-
Clone and install dependencies:
git clone https://github.com/nodejs-boot/sample-fastify.git cd sample-fastify pnpm install -
Start development server:
pnpm star #or with nodemon for hot reload pnpm dev
-
Access the application:
- API: http://localhost:3000/api
- Swagger UI: http://localhost:3000/docs
- Actuator Metrics/info: http://localhost:3000/actuator
- Health Check: http://localhost:3000/actuator/health
-
Actuator Endpoints:
/actuator/health- Application health status/actuator/info- Application info/actuator/git- Git info/actuator/config- Current configuration/actuator/metrics- Application metrics/actuator/prometheus- Prometheus metrics/actuator/controllers- Registered controllers/actuator/interceptors- Registered interceptors/actuator/middlewares- Registered middlewares
| Script | Description |
|---|---|
pnpm start |
Build and start production server |
pnpm start:prod |
Build and start with NODE_ENV=production |
pnpm dev |
Start development server with hot reload |
pnpm build |
Compile TypeScript to JavaScript |
pnpm postbuild |
Run Node-Boot AOT (Ahead of Time) compilation |
pnpm clean:build |
Remove dist directory |
pnpm lint |
Run ESLint |
pnpm lint:fix |
Run ESLint with auto-fix |
pnpm format |
Check code formatting |
pnpm format:fix |
Format code with Prettier |
pnpm test |
Run tests with Jest |
pnpm typecheck |
Type check without compilation |
pnpm nodeboot:update |
Update Node-boot framework - Update all @nodeboot packages |
pnpm rebuild:sqlite |
Rebuild SQLite native bindings |
pnpm create:migration |
Create new TypeORM migration |
The application uses YAML-based configuration with environment overrides:
app-config.yaml- Main application configurationapp-config.local.yaml- Local development overridesapp-credentials.local.yaml- Local credentials (git-ignored)
app:
name: "fast-service"
platform: "node-boot"
environment: "development"
port: 3000
api:
routePrefix: "/api"
validations:
enableDebugMessages: true
stopAtFirstError: true
server:
cors:
origin: "*"
methods: ["GET", "POST"]src/
βββ app.ts # Main application class with decorators
βββ server.ts # Application entry point
βββ auth/ # Authentication & authorization
βββ clients/ # HTTP clients for external services
βββ config/ # Configuration classes
βββ controllers/ # REST API controllers
βββ exceptions/ # Custom exception handlers
βββ interfaces/ # TypeScript interfaces
βββ middlewares/ # Custom middleware
βββ models/ # DTOs and data models
βββ persistence/ # Database layer
β βββ entities/ # TypeORM entities
β βββ repositories/ # Custom repositories
β βββ migrations/ # Database migrations
β βββ listeners/ # Entity event listeners
βββ services/ # Business logic services
Main application class with feature decorators:
@EnableDI() // Enable Dependency Injection
@EnableOpenApi() // Enable OpenAPI (Swagger) documentation
@EnableSwaggerUI() // Enable SwaggerUI
@EnableAuthorization() // Enable Authorization
@EnableActuator() // Enable Actuator (health, metrics)
@EnableRepositories() // Enable persistence with TypeORM, transactions, migrations, listeners
@EnableScheduling() // Enable scheduled tasks
@EnableHttpClients() // Enable declarative HTTP clients
@EnableValidations() // Enable request/response validations
@EnableComponentScan() // Enable component scanning with AOT support
export class SampleApp implements NodeBootApp {
start(): Promise<NodeBootAppView> {
return NodeBoot.run(FastifyServer);
}
}REST API endpoints using decorators for routing and validation:
@Controller("/users", "v1")
export class UsersController {
@Get("/")
async getUsers(): Promise<User[]> {
return this.userService.findAllUser();
}
}Key Features:
- Automatic route registration
- Built-in validation
- Swagger documentation generation
- Exception handling
Business logic layer with dependency injection:
@Service()
export class UserService {
constructor(
private readonly userRepository: UserRepository,
private readonly logger: Logger
) {}
}Key Features:
- Singleton instances
- Constructor injection
- Transaction support with
@Transactional - Logging integration
TypeORM entities for database mapping:
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
email: string;
}Node-Boot Data repositories extending TypeORM Repository:
@DataRepository(User)
export class UserRepository extends Repository<User> {
// Custom query methods
}Key Features:
- Automatic transaction management
- Custom naming strategies
- Entity event listeners
- Migration support
Data Transfer Objects with validation and OpenAPI metadata:
@Model()
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
}Custom middleware for cross-cutting concerns:
LoggingMiddleware- Request/response loggingCustomErrorHandler- Global error handling
Type-safe configuration with @ConfigurationProperties:
@ConfigurationProperties("app")
export class AppConfigProperties {
name: string;
port: number;
environment: string;
}The application demonstrates various Node-Boot starters and features:
| Feature | Decorator | Description |
|---|---|---|
| Dependency Injection | @EnableDI |
TypeDI container integration |
| OpenAPI | @EnableOpenApi |
Automatic API documentation |
| Swagger UI | @EnableSwaggerUI |
Interactive API explorer |
| Authorization | @EnableAuthorization |
Role-based access control |
| Actuator | @EnableActuator |
Health checks and metrics |
| Persistence | @EnableRepositories |
TypeORM integration + Transactions management |
| Scheduling | @EnableScheduling |
Cron jobs and scheduled tasks |
| HTTP Clients | @EnableHttpClients |
Declarative HTTP clients |
| Validations | @EnableValidations |
Request/response validation |
| Component Scan | @EnableComponentScan |
AOT compilation support |
Development server uses nodemon for automatic restarts:
// nodemon.json
{
"watch": ["src"],
"ext": "ts,json,yaml",
"exec": "ts-node src/server.ts"
}- Development: SQLite database (
fastify-sample.db) - Migrations: Use
pnpm create:migrationto create new migrations and then add the@Migrationdecorator to the generated migration class. - Seeding: Initial users loaded via
users.init.ts
The sample uses SQLite by default for simplicity and portability. The database file (fastify-sample.db) is created automatically in the project root.
The Node-Boot starter persistence package supports all TypeORM-compatible databases. You can easily switch by updating your configuration:
- SQL Databases: PostgreSQL, MySQL, MariaDB, SQLite, Microsoft SQL Server, Oracle, CockroachDB
- NoSQL Databases: MongoDB
-
Install the appropriate database driver:
# PostgreSQL pnpm add pg pnpm add -D @types/pg # MySQL/MariaDB pnpm add mysql2 # MongoDB pnpm add mongodb # SQL Server pnpm add mssql # Oracle pnpm add oracledb
-
Update your configuration file (
app-config.yamlorapp-config.local.yaml):SQLite Example (default):
persistence: type: "better-sqlite3" synchronize: false # False, meaning that the application rely on migrations cache: true migrationsRun: true better-sqlite3: database: "fastify-sample.db" transactions: # Controls how many hooks (`commit`, `rollback`, `complete`) can be used simultaneously. # If you exceed the number of hooks of same type, you get a warning. This is a useful to find possible memory leaks. # You can set this options to `0` or `Infinity` to indicate an unlimited number of listeners. maxHookHandlers: 10 # Controls storage driver used for providing persistency during the async request timespan. # You can force any of the available drivers with this option. # By default, the modern AsyncLocalStorage will be preferred, if it is supported by your runtime. storageDriver: "AUTO"
PostgreSQL Example:
persistence: type: "postgres" synchronize: false # False, meaning that the application rely on migrations cache: true migrationsRun: true postgres: host: "localhost" port: 5432 username: "your_username" password: "your_password" database: "your_database"
MySQL Example:
datasource: type: "mysql" synchronize: false # False, meaning that the application rely on migrations cache: true migrationsRun: true mysql: host: "localhost" port: 3306 username: "root" password: "password" database: "fastify_sample"
MongoDB Example:
persistence: type: "mongodb" cache: false mongodb: database: "facts" #url: mongodb://localhost:27017/?directConnection=true url: mongodb+srv://${DATABASE_CREDS}@db-name.mongodb.net/?retryWrites=true&w=majority&appName=sample-fastify
-
Environment-specific Configuration: Use
app-config.local.yamlfor local development orapp-credentials.local.yamlfor sensitive credentials:# app-credentials.local.yaml (git-ignored) postgres: username: "your_username" password: "your_password"
For production environments, use environment variables or secure configuration management:
mysql:
username: "${DB_USERNAME}"
password: "${DB_PASSWORD}"
host: "${DB_HOST:localhost}"
port: "${DB_PORT:5432}"
database: "${DB_NAME}"The Node-Boot starter persistence package provides:
- Automatic Connection Management - Connections are managed automatically
- Transaction Support - Use
@Transactionaldecorator for transaction management - Migration System - TypeORM migrations with Node-Boot decorators
- Entity Event Listeners - Lifecycle hooks for entities
- Repository Pattern - Custom repositories with
@DataRepository - Connection Pooling - Built-in connection pool management
# Create new migration
pnpm create:migrationNote: After creating the migration class, add the
@Migrationdecorator to the generated class to register it. Build and run the application to execute pending migrations at bootstrap.
import {MigrationInterface, QueryRunner} from "typeorm";
import {Migration} from "@nodeboot/starter-persistence";
@Migration()
export class Migration1701786331338 implements MigrationInterface {
async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "nb-user" ADD COLUMN "name" varchar(255)`);
}
async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "nb-user" DROP COLUMN "name"`);
}
}For detailed database configuration options, visit the Node-Boot Starter Persistence.
- Framework: Jest with SWC compiler
- Configuration:
jest.config.js - Run tests:
pnpm test
- Linting: ESLint with TypeScript rules
- Formatting: Prettier with import organization
- Type Checking: Strict TypeScript configuration
app.ts- Main application bootstrap with feature decoratorsserver.ts- Application entry pointpackage.json- Dependencies and scriptstsconfig.json- TypeScript configurationapp-config.yaml- Application configurationDockerfile- Container configuration
-
Build the application:
pnpm build
-
Start production server:
pnpm start:prod
-
Docker deployment:
- Build docker image
docker build -f Dockerfile -t fastify-sample .- Run docker image
docker run --rm -it -p 3000:3000 fastify-sample
- Check container filesystem
docker run -t -i fastify-sample /bin/sh
Access the interactive API documentation at: http://localhost:3000/docs

