Skip to main content

Node.js / Fastify Scaffold

A production-ready Node.js backend built on Fastify 4 with TypeScript.

Generate

idp scaffold new --type nodejs --name my-service

Project structure

my-service/
├── src/
│ ├── routes/ # Route definitions — thin HTTP-to-controller wrappers
│ │ ├── index.ts
│ │ └── health.route.ts
│ ├── controllers/ # Request/response handling, input validation
│ │ └── health.controller.ts
│ ├── services/ # Business logic — pure, no HTTP knowledge
│ │ └── health.service.ts
│ ├── dal/ # Data Access Layer — DB / external calls
│ │ └── health.repository.ts
│ ├── middlewares/
│ │ ├── auth.middleware.ts
│ │ ├── sanitize.middleware.ts
│ │ └── cors.middleware.ts
│ ├── exceptions/
│ │ ├── AppError.ts
│ │ ├── NotFoundError.ts
│ │ ├── ValidationError.ts
│ │ └── UnauthorizedError.ts
│ ├── handlers/
│ │ └── globalErrorHandler.ts
│ ├── config/
│ │ ├── env.ts # Zod schema — fails fast if required vars missing
│ │ └── logger.ts # Pino with request-ID correlation
│ ├── utils/
│ │ └── response.helper.ts
│ └── app.ts # Fastify app bootstrap
├── tests/
│ ├── unit/
│ └── integration/
├── .github/workflows/
│ ├── ci.yml
│ └── cd.yml
├── .env.example
├── Dockerfile
├── docker-compose.yml
├── jest.config.ts
└── package.json

What's included

Layered architecture

HTTP Request

Route (validates shape, delegates)

Controller (parse + respond)

Service (business rules)

Repository (DB / API calls)

Error handling

All errors thrown anywhere in the chain are caught by the global Fastify error handler. Custom error classes map to HTTP status codes automatically:

throw new NotFoundError('User not found');
// → 404 { success: false, error: { code: 'NOT_FOUND', message: 'User not found' } }

Environment validation

On startup, all required env vars are validated against a Zod schema. The process exits with a clear error if any var is missing or invalid — no silent failures in production.

Response envelope

All responses follow a consistent shape:

{
"success": true,
"data": { ... },
"meta": { "timestamp": "...", "requestId": "..." }
}

Running locally

cd my-service
npm install
cp .env.example .env
npm run dev

Open http://localhost:3000/health.

Scripts

ScriptDescription
npm run devStart with hot-reload
npm run buildCompile TypeScript
npm run startStart compiled output
npm testRun unit + integration tests
npm run lintESLint check

Environment variables

VariableRequiredDefaultDescription
PORTNo3000HTTP port
NODE_ENVNodevelopmentdevelopment / production
LOG_LEVELNoinfoPino log level
CORS_ORIGINSNo*Allowed CORS origins (comma-separated)