Skip to content

santoshshinde2012/node-boilerplate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

678 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Production-ready skeleton for Node.js + TypeScript services with hardened security defaults.

Quality Gate Status Github action workflow status maintainability test_coverage

Introductions

Purpose

A batteries-included starting point for production Node.js services. Out of the box you get a hardened Express setup, structured JSON logging, encrypted-response support, Docker hardening, request tracing, graceful shutdown and a CI pipeline wired for SonarCloud / Snyk / CodeQL / njsscan / Code Climate.

Star History

Star History Chart

Highlights

  • Quick start – TypeScript, ESLint flat config, Prettier, Husky, Jest with coverage.
  • Hardened security defaults
    • Helmet (HSTS in prod), x-powered-by disabled, x-request-id propagation.
    • Allow-list driven CORS via CORS_ORIGINS.
    • Global rate limiter (express-rate-limit, draft-7 standard headers).
    • Body size capped at 1 MB by default (configurable via BODY_LIMIT).
    • PBKDF2-HMAC-SHA512 key derivation at OWASP-2023 strength (600 000 iters) + AES-256-GCM with per-message salt + IV embedded in the ciphertext.
    • Production-mode filtering of system endpoints (no process.env, network interfaces or OS user info on the wire).
    • Centralized config validation – the app refuses to boot with bad/missing values.
  • Production runtime
    • Multi-stage Dockerfile on node:22-bookworm-slim, runs as non-root with tini as PID 1, healthcheck baked in.
    • docker-compose.yml with read_only, cap_drop: ALL, no-new-privileges and resource limits.
    • Graceful shutdown on SIGINT / SIGTERM with a 10 s drain window.
    • Structured Winston logging (separate error.log, JSON format, level via LOG_LEVEL).
    • HTTP server timeouts (keepAlive, headersTimeout, requestTimeout) tuned for behind-LB deployments.
  • Observability
    • /healthz and /readyz liveness/readiness endpoints (skipped from rate-limit).
    • Per-request id middleware (echoes/forwards x-request-id, falls back to crypto.randomUUID()).
    • Access log with status, duration, IP, user agent and request id.
  • Continuous integration
    • GitHub Actions matrix (Node 20.x / 22.x).
    • SonarCloud, Snyk monitor, CodeQL, njsscan SARIF upload, Code Climate.
  • Documentation
    • Swagger UI mounted at /docs in non-production.
    • Postman collection in wiki/postman.

Core Runtime Modules

Package Purpose
express HTTP framework
helmet Secure HTTP headers
cors Cross-origin allow-list
compression gzip / brotli compression
express-rate-limit Per-IP rate limiting
winston Structured JSON logging
dotenv .env loading
swagger-ui-express API docs in non-prod
http-status-codes Symbolic HTTP status codes

Requirements

  • Node.js >= 20.x (tested on 20 and 22)
  • npm >= 10

Start the application in development mode

git clone https://github.com/santoshshinde2012/node-boilerplate.git
cd node-boilerplate
cp .env.example .env
npm install
npm run dev

Start the application in production mode

npm ci --omit=dev   # or `npm install` for full local dev
npm run build
NODE_ENV=production npm run start

Always populate .env from .env.example before going to production. The boot will fail-fast if APPLY_ENCRYPTION=true is set without a valid SECRET_KEY (>= 16 chars).

Run inside Docker

docker compose up --build
# or
docker build -t node-boilerplate .
docker run --rm -p 8080:8080 --env-file .env node-boilerplate

The runtime image is multi-stage, runs as user nodeuser (uid 1001), drops all Linux capabilities and exposes a HEALTHCHECK against /healthz.

Configuration

All configuration lives in environment variables (see .env.example).

Variable Default Notes
NODE_ENV development One of development, test, staging, production. Legacy prod aliased to production.
PORT 8080 TCP port.
LOG_LEVEL info (prod) / debug Winston level.
APPLY_ENCRYPTION false Encrypt response payloads on the wire.
SECRET_KEY none Required when encryption is enabled. Min 16 chars.
ENCRYPTION_SALT none Optional fixed salt; otherwise a per-message salt is embedded in the ciphertext.
CORS_ORIGINS empty Comma-separated allow-list. Use * for any (dev only).
BODY_LIMIT 1mb Max JSON / urlencoded body size.
RATE_LIMIT_WINDOW_MS 60000 Rate-limiter window.
RATE_LIMIT_MAX 120 Max requests per IP per window.
TRUST_PROXY false Set to true when running behind a trusted reverse proxy (nginx/ELB/Cloudflare).
EXPOSE_SYSTEM_ROUTES true (non-prod) Disable diagnostic /v1/system/* endpoints.

Project structure

Path Description
src/App.ts Express app composition (middleware + routes + error handler).
src/server.ts HTTP server bootstrap and graceful shutdown.
src/config/ Centralized, validated environment config.
src/abstractions/ Shared abstract classes and interfaces (e.g. ApiError).
src/components/ Feature controllers grouped by domain.
src/lib/ Reusable utilities (logger, crypto).
src/middleware/ Cross-cutting middleware (request id, request logger, error handler).
src/types/ Shared TypeScript types.
src/utils/ Pure helper functions.
tests/unit-tests/ Jest unit tests.
tests/integration-tests/ Supertest integration tests.
wiki/ Diagrams, instructions, Postman collection.
Dockerfile / docker-compose.yml Hardened container build.

Workflow

Workflow

Default routes

Method Path Notes
GET / Liveness ping (returns { "message": "base path" }).
GET /healthz Health probe (uptime + timestamp).
GET /readyz Readiness probe.
GET /web Demo of header-based auth (requires x-internal-authorization and Authorization).
GET /docs Swagger UI (non-production only).
GET /v1/system/info System info (filtered in production).
GET /v1/system/time Server time.
GET /v1/system/usage Process + system memory and CPU usage.
GET /v1/system/process Process info (filtered in production).
GET /v1/system/error Sample error path.

Every response includes the x-request-id header (echoed if the client supplied one and it matches ^[A-Za-z0-9._-]{1,128}$, otherwise a freshly minted UUID).

Encryption

Set APPLY_ENCRYPTION=true and provide SECRET_KEY. Responses produced via BaseController#send are then base64 AES-256-GCM ciphertexts of the form:

salt(16) || ciphertext || iv(12) || tag(16)

The salt is randomized per-message and embedded so decrypt() works across processes/hosts without shared in-memory state. PBKDF2 derivation uses 600 000 iterations of HMAC-SHA512 (OWASP 2023 guidance).

Swagger / Postman

Swagger API Documentation

Quality gates

npm run typecheck     # tsc --noEmit
npm run lint          # eslint
npm run format        # prettier
npm test              # jest with coverage
npm run audit:prod    # npm audit --omit=dev --audit-level=high

CI runs all of the above plus SonarCloud / Snyk / CodeQL / njsscan / Code Climate.

Security disclosure

See SECURITY.md for how to responsibly report a vulnerability.

References

Notes

Husky pre-commit hook is not executable by default

chmod ug+x .husky/*
chmod ug+x .git/hooks/*

Tutorials


Connect with me on