Lumitech Node.js Fastify Template
Welcome to the Lumitech Node.js Fastify Template. This template provides a well-organized starting point for building back-end applications in Node.js, featuring Swagger-based API documentation, ready-to-use Docker configuration, and Awilix for dependency injection. With well-defined architectural patterns, it helps ensure the code remains maintainable, scalable, and testable, especially as the application grows.
Lumitech is a custom software development company providing professional services worldwide. We partner with technology businesses globally helping them to build successful engineering teams and create innovative software products. Weβre a global team of software engineers, AI and ML specialists, product managers, and technology experts who have achieved a 600% growth rate since 2022. When a rocket launches toward the moon, it doesnβt stop halfway. Neither do we.
- TypeScript - programming language;
- Node.js - JavaScript runtime;
- Fastify - HTTP framework;
- Zod - validation;
- Swagger - API documentation;
- Awilix - Dependency Injection container;
- PostgreSQL - relational database;
- Prisma - database ORM;
- Vitest - testing framework.
npm install- install the dependencies locally;- Create a
.envfile from.env.example; - Launch Docker Compose with the
docker compose upcommand.
Since both the Node.js server and PostgreSQL database run inside Docker containers, the database connection uses the docker compose network.
Inside the Node.js container, use postgresdb as the database host.
To run migrations from a host machine:
- Launch docker containers -
docker compose up; - Update the
.envfile, changingDATABASE_URLhost frompostgresdbtolocalhost; - Run
npm run prisma:migrate:create- create SQL migration file; - Name the new migration and verify the SQL code generated;
- Run
npm run prisma:migrate:apply- apply the migration to the database; - Revert the
DATABASE_URLin.envback topostgresdbso that the Node.js container can connect to the database after a rebuild.
Unit tests ensure individual components function correctly in isolation. The template uses a Vitest testing framework for comprehensive test coverage:
npm run test:unit- run all unit tests with detailed output in the terminal;npm run test:unit:ui- launch the interactive UI test runner.
This template utilizes Awilix for Dependency Injection (DI), which helps in managing application dependencies efficiently.
- Encapsulation & Maintainability: Keeps the code modular and easier to maintain.
- Testability: Improves unit testing by allowing easy mocking of dependencies.
- Cleaner Architecture: Enhances readability and organization.
- Implemented Patterns: Uses Dependency Inversion, Inversion of Control, and Singleton.
Awilix is configured as a Fastify plugin, allowing services, handlers, repositories and custom dependencies to be injected dynamically. It enables clean and organized code by managing dependencies automatically. The DI container is registered in src/plugins/awilix.ts.
Define an email service abstraction layer in the lib directory.
src/lib/emails/index.ts
export type EmailService = {
sendEmail: (emailRecipient: string, p: EmailOptions) => Promise<void>;
};
export const createEmailService = (
config: EnvConfig,
log: FastifyBaseLogger
): EmailService => {
const emailProvider = new EmailProvider({ secretKey: config.secretKey });
return {
sendEmail: async (emailRecipient, email) => {
...
await emailProvider.sendEmail(emailRecipient, email);
...
},
};
};Register the email service in the DI container.
src/plugins/awilix.ts
// Register dependencies from plugins and libraries
fastify.di.register({
log: asValue(fastify.log),
config: asValue(fastify.config),
emailService: asFunction(createEmailService),
});Use the email service by specifying its name in the function parameters.
src/modules/user/user.service.ts
export type UserService = {
sendWelcomeEmail: (
userId:string,
) => Promise<UserEventsResponseBody>;
};
export const createUserService = (
emailService: EmailService,
): UserService => ({
sendWelcomeEmail: async (userId) => {
...
await emailService.sendEmail(email, {...});
...
},
});
addDIResolverName(createService, "userService"); // Define a unique DI container name for automatic loading.This template provides a Dockerfile for building a production-ready Node.js image and a docker-compose.yml file for local development. By default, Docker Compose starts two services:
- Node.js β Runs the application inside a container using the provided Dockerfile.
- PostgreSQL β Spins up a PostgreSQL database.
Is is possible can add more services (for example, Redis) by including them in docker-compose.yml and configuring their networking and environment variables.
This setup allows to quickly bootstrap a fully containerized development environment without installing any dependencies locally other than Docker itself.
This template includes Swagger for automatic API documentation generation, making it easy to document REST API endpoints.
- Swagger Integration: The Fastify Swagger plugin automatically generates API documentation from route schemas.
- Route Description: It is possible to categorize endpoints by tags and describe them in the route schema.
- Authorization: Secure the documentation with a password.
Example route with Swagger options:
fastify.post(
"/sign-up",
{
schema: {
tags: ["auth"], // Categorizes the route under the specified tags.
summary: "Create a new user account".
description: "Create a new user within the system",
body: signUpBodySchema,
response: {
200: signUpResponseSchema,
},
},
},
authHandler.signUp
);The template provides an automatic repository generator based on the Prisma Schema data model. It includes a set of commonly used CRUD operations for any entity.
The generator is located in src/database/repositories/generate.repository.ts.
const userRepository = generateRepository(prismaClient, "User");
const user = await userRepository.create({
data: {},
select: {},
});
// Methods available: create, update, delete, etc.
await userRepository.delete({
where: {},
});We use Commitlint to ensure that commit messages adhere to the conventional commit format. This standardizes the commit history and simplifies changelog generation.
The basic format is:
type(scope?): subjectExamples:
chore: update dependenciesfix(message): correct API response errorfeat(auth): add JWT authentication
A more detailed description you can see in Conventional Commits documentation.
The project is organized into several parts to promote a modular design and separation of concerns:
This directory manages everything related to data persistence and interaction with the database.
- The
prismasubfolder houses the Prisma schema (schema.prisma) and migration files that define the application's data model to the database. - The
repositoriessubfolder contains repository modules for each entity. These repositories provide a unified API for CRUD operations (e.g., ingenerate.repository.ts) and custom logic for data access (e.g.,message.repository.tsfor the Message model).
This directory contains feature-based modules which encapsulate business logic along with the HTTP layer.
Each module includes:
- Routes: Define endpoint paths and attach them to the appropriate handlers (e.g.,
message.route.tsfor message-related endpoints). - Handlers: Manage request processing and response formatting by invoking corresponding services (e.g.,
message.handler.ts). - Services: Implement business logic, coordinate with repositories, and use the necessary third-party libraries from
src/lib(e.g.,message.service.ts).
The directory is dedicated to Fastify plugins which extend the server capabilities. Each file registers a plugin that adds functionality to the Fastify instance.
Plugins included:
- Environment Configuration (
env.ts): Loads and validates environment variables. - Database Management (
prisma.ts): Sets up aPrismaClientand manages database connection. - Authentication (
jwt.ts): Configures JSON Web Token handling for security. - API Documentation (
swagger.tsandzod.ts): Integrates Swagger for API documentation and Zod for schema validation. - Dependency Injection (
awilix.ts): Registers and manages service dependencies using Awilix. - Error Handling (
error.ts): Provides a centralized mechanism for managing application errors.
This directory serves as an abstraction layer for third-party services and integrations. It is designed to encapsulate interactions with external services such as BullMQ for job processing, Stripe for payment processing, email sending services, file storage providers (e.g. AWS S3, GCP Cloud Storage), and more.
These abstraction layers are registered in the Awilix container and imported by services as needed. Additionally, this folder includes validation schemas using Zod for different modules, as well as utility functions and helpers that support the overall application infrastructure.
Global TypeScript types and declarations used across the project.
This directory contains all test files organized to mirror the structure of the source code.
- The
unitsubdirectory contains unit tests that verify the functionality of individual components in isolation.- Tests for library components are in the
libsubdirectory, ensuring third-party integrations work as expected. - Tests for application modules are in the
modulessubdirectory, organized by feature to test services.
- Tests for library components are in the
- Each test file follows the naming convention of
[component-name].test.tsto clearly identify what's being tested.
.
βββ commitlint.config.js
βββ docker-compose.yml
βββ Dockerfile
βββ eslint.config.mjs
βββ nodemon.json
βββ package.json
βββ package-lock.json
βββ README.md
βββ src
βΒ Β βββ database
βΒ Β βΒ Β βββ prisma
βΒ Β βΒ Β βΒ Β βββ migrations
βΒ Β βΒ Β βΒ Β βΒ Β βββ ...
βΒ Β βΒ Β βΒ Β βββ prisma.type.ts
βΒ Β βΒ Β βΒ Β βββ schema.prisma
βΒ Β βΒ Β βββ repositories
βΒ Β βΒ Β βββ generate.repository.ts
βΒ Β βΒ Β βββ ...
βΒ Β βββ lib
βΒ Β βΒ Β βββ ...
βΒ Β βΒ Β βββ validation
βΒ Β βΒ Β βββ feature
βΒ Β βΒ Β βββ index.ts
βΒ Β βΒ Β βββ feature.schema.ts
βΒ Β βββ modules
βΒ Β βΒ Β βββ application.ts
βΒ Β βΒ Β βββ feature
βΒ Β βΒ Β βββ index.ts
βΒ Β βΒ Β βββ feature.handler.ts
βΒ Β βΒ Β βββ feature.route.ts
βΒ Β βΒ Β βββ feature.service.ts
βΒ Β βββ plugins
βΒ Β βΒ Β βββ awilix.ts
βΒ Β βΒ Β βββ cors.ts
βΒ Β βΒ Β βββ env.ts
βΒ Β βΒ Β βββ error.ts
βΒ Β βΒ Β βββ jwt.ts
βΒ Β βΒ Β βββ prisma.ts
βΒ Β βΒ Β βββ swagger.ts
βΒ Β βΒ Β βββ zod.ts
βΒ Β βββ types
βΒ Β β βββ env.type.ts
βΒ Β β βββ index.d.ts
βΒ Β βββ index.ts
βΒ Β βββ server.ts
βββ test
βΒ Β βββ unit
βΒ Β βββ lib
βΒ Β βΒ Β βββ ...
βΒ Β βββ modules
βΒ Β βββ feature
βΒ Β βββ feature-service.test.ts
βΒ Β βββ ...
βββ tsconfig.json
- Fastify example - a brief example of core Fastify features;
- Guide to plugins - encapsulation and decorators in Fastify.
