Starting a new Node.js API project shouldn't mean wasting 2 hours on boilerplate setup. Here are 5 production-ready patterns every backend developer should have bookmarked.
Why Boilerplates Matter in 2026
With AI coding assistants everywhere, the bottleneck isn't writing code—it's wiring up the right structure. A well-architected boilerplate saves you from:
- Security mistakes (missing helmet, CORS misconfig, no rate limiting)
- Auth headaches (JWT expiry, refresh token rotation)
- Deployment surprises (no Docker config, no health checks)
Let's cut straight to the patterns.
1. The Minimal Secure Starter
Every API needs these three things from day one:
const express = require('express');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const app = express();
// Security headers (prevents XSS, clickjacking, etc.)
app.use(helmet());
// Rate limiting (100 req/15min per IP)
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 });
app.use('/api', limiter);
// Health check (required for Docker/K8s)
app.get('/health', (req, res) => res.json({ status: 'ok', uptime: process.uptime() }));
Don't skip helmet. It sets 11 security headers in one line. Running without it is like leaving your front door unlocked.
2. JWT Auth with Refresh Token Rotation
The pattern most tutorials get wrong—they forget about refresh tokens:
const generateTokens = (payload) => {
const accessToken = jwt.sign(payload, JWT_SECRET, { expiresIn: '15m' });
const refreshToken = jwt.sign(payload, REFRESH_SECRET, { expiresIn: '30d' });
return { accessToken, refreshToken };
};
// On refresh: invalidate old token, issue new pair
router.post('/refresh', (req, res) => {
const { refreshToken } = req.body;
if (!refreshTokens.has(refreshToken)) {
return res.status(401).json({ error: 'Invalid token' });
}
const decoded = jwt.verify(refreshToken, REFRESH_SECRET);
const tokens = generateTokens({ id: decoded.id, role: decoded.role });
// Rotate: delete old, store new
refreshTokens.delete(refreshToken);
refreshTokens.add(tokens.refreshToken);
res.json(tokens);
});
Key insight: Short-lived access tokens (15 min) + long-lived refresh tokens (30 days) = security without UX pain. Rotate refresh tokens on every use to prevent replay attacks.
3. Pagination That Actually Scales
const paginate = (req, data) => {
const { page = 1, limit = 10, sort = 'createdAt', order = 'desc' } = req.query;
const sorted = [...data].sort((a, b) =>
order === 'desc' ? (b[sort] > a[sort] ? 1 : -1) : (a[sort] > b[sort] ? 1 : -1)
);
const total = sorted.length;
const start = (parseInt(page) - 1) * parseInt(limit);
return {
data: sorted.slice(start, start + parseInt(limit)),
pagination: { total, page: +page, limit: +limit, totalPages: Math.ceil(total / +limit) }
};
};
Always return pagination metadata. Your frontend dev will thank you, and your API won't choke when you hit 10k records.
4. The Dockerfile Every Node App Needs
# Multi-stage: builder + production
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:20-alpine
WORKDIR /app
RUN addgroup -S app && adduser -S app -G app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER app
EXPOSE 3000
HEALTHCHECK --interval=30s CMD node -e "require('http').get('http://localhost:3000/health', r => process.exit(r.statusCode === 200 ? 0 : 1))"
CMD ["node", "src/index.js"]
Why multi-stage? Your final image goes from ~900MB to ~180MB. Non-root user prevents container escape attacks. Health check = auto-restart on failure in Kubernetes/Compose.
5. Error Handling That Doesn't Leak Secrets
// Global error handler — always last middleware
app.use((err, req, res, next) => {
// Log full error server-side
console.error({
message: err.message,
stack: err.stack,
url: req.url,
method: req.method
});
// Send safe error to client
res.status(err.status || 500).json({
error: process.env.NODE_ENV === 'production'
? 'Internal server error' // Never leak stack traces in prod
: err.message
});
});
One of the most common security mistakes: stack traces in production responses. The fix is one line—check NODE_ENV.
The Full Package
These 5 patterns are the core of any production Node.js API. Want them pre-wired with tests, input validation, Docker Compose with MongoDB + Redis, and a Postman collection?
I put together a complete Node.js REST API Boilerplate Pack with all 5 ready-to-use templates + documentation → guittet.gumroad.com
Quick Reference
| Pattern | Why It Matters |
|---|---|
| Helmet + Rate Limit | Security baseline, zero effort |
| JWT with rotation | Stateless auth, replay-attack resistant |
| Pagination | Scales to millions of records |
| Multi-stage Docker | 5x smaller images, non-root security |
| Error handling | Never leak internals to attackers |
Save this as your Node.js API checklist. Ship it once, reuse forever.
Top comments (0)