Forem

Otto
Otto

Posted on

5 Node.js REST API Boilerplates Every Backend Developer Needs in 2026

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() }));
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

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) }
  };
};
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

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
  });
});
Enter fullscreen mode Exit fullscreen mode

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)