Enterprise-grade Node.js backend boilerplate with TypeScript, Express, Prisma, and comprehensive error handling.
- β Routes > Controller > Services architecture
- β Comprehensive error handling with custom error classes
- β Structured logging (development & production modes)
- β Type-safe configuration with Zod validation
- β Request validation middleware using Zod
- β Standardized API responses
- β
API versioning (
/api/v1) - β Graceful shutdown handling
- β Database connection management (Prisma + SQLite)
- β Request logging with timing
- β 404 handling
- β Async error handling wrapper
- β TypeScript strict mode
- β Kebab-case file naming
src/
βββ config/ # Configuration management
β βββ config.ts # Type-safe environment config
β βββ constants.ts # Application constants
βββ controllers/ # Request handlers
β βββ health.controller.ts
βββ middleware/ # Express middleware
β βββ async-handler.ts
β βββ error-handler.ts
β βββ not-found.ts
β βββ request-logger.ts
β βββ validate-request.ts
βββ routes/ # API routes
β βββ health.route.ts
β βββ index.ts # Route aggregator
βββ services/ # Business logic
β βββ health.service.ts
βββ types/ # TypeScript types
β βββ api.types.ts
β βββ express.d.ts
βββ utils/ # Utilities
β βββ app-error.ts # Custom errors
β βββ logger.ts # Structured logger
β βββ response-formatter.ts
βββ index.ts # Application entry point
- Runtime: Node.js
- Language: TypeScript
- Framework: Express 5
- Database: SQLite (via Prisma)
- ORM: Prisma
- Validation: Zod
- Dev Tools: tsx (TypeScript execution)
# Install dependencies
npm install
# Generate Prisma client
npm run prisma:generate
# Run database migrations
npm run prisma:migratenpm run dev# Build
npm run build
# Start
npm start# Generate Prisma client
npm run prisma:generate
# Run migrations
npm run prisma:migrate
# Open Prisma Studio
npm run prisma:studio
# Reset database
npm run prisma:reset
# Push schema changes
npm run db:push
# Seed database
npm run db:seedGET /api/v1/health- Comprehensive health statusGET /api/v1/health/ping- Simple ping
All API responses follow this structure:
{
success: boolean,
data?: any,
error?: {
message: string,
code: string,
details?: any
},
metadata?: {
timestamp: string,
requestId?: string,
pagination?: {
page: number,
limit: number,
total: number,
totalPages: number
}
}
}Route - Defines endpoints and applies middleware
router.get("/", asyncHandler(controller.method));Controller - Handles HTTP requests/responses
method = asyncHandler(async (req, res) => {
const data = await this.service.method();
ResponseFormatter.success(res, data);
});Service - Contains business logic
async method() {
// Business logic here
return data;
}AppError- Base error classValidationError- 400 Bad RequestUnauthorizedError- 401 UnauthorizedForbiddenError- 403 ForbiddenNotFoundError- 404 Not FoundConflictError- 409 ConflictInternalServerError- 500 Internal Server Error
throw new NotFoundError("User not found");
throw new ValidationError("Invalid email", "INVALID_EMAIL");// src/services/user.service.ts
export class UserService {
async getUsers() {
return await prisma.user.findMany();
}
}// src/controllers/user.controller.ts
export class UserController {
private userService = new UserService();
getUsers = asyncHandler(async (req, res) => {
const users = await this.userService.getUsers();
ResponseFormatter.success(res, users);
});
}// src/routes/user.route.ts
const router = Router();
const userController = new UserController();
router.get("/", asyncHandler(userController.getUsers));
export default router;// src/routes/index.ts
import userRoute from "./user.route.js";
router.use(`${apiPrefix}/users`, userRoute);Using Zod schemas:
import { z } from "zod";
import { validateRequest } from "../middleware/validate-request.js";
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2),
age: z.number().min(18).optional(),
});
router.post(
"/users",
validateRequest({ body: createUserSchema }),
asyncHandler(userController.create)
);import { logger } from "./utils/logger.js";
logger.info("User created", { userId: 123 });
logger.error("Database error", error);
logger.warn("Deprecated API used");
logger.debug("Debug information");Environment variables are validated using Zod:
NODE_ENV=development
PORT=3000
DATABASE_URL=file:./dev.db
GEMINI_API_KEY=your_api_key
CORS_ORIGIN=*
LOG_LEVEL=info- β TypeScript strict mode enabled
- β
No
anytypes (except where necessary) - β Async error handling
- β Request validation
- β Structured logging
- β Graceful shutdown
- β Database connection pooling
- β Environment validation
- β Consistent code style
- β Kebab-case file naming
ISC
Furkan ΓakΔ±cΔ±