Starting from a single server file
Every Express app starts more or less the same way - create an app instance, tell it to parse JSON bodies, and start listening on a port.
import express from "express";
const app = express();
app.use(express.json());
app.listen(3000, () => {
console.log("Server running on port 3000");
});
Splitting routes into their own files
Once you have more than two or three endpoints, keeping everything in one file gets messy fast. Move related routes into their own router.
// routes/posts.js
import { Router } from "express";
const router = Router();
router.get("/", async (req, res) => {
const posts = await Post.find({}).lean();
res.json({ success: true, data: posts });
});
router.post("/", async (req, res) => {
const post = await Post.create(req.body);
res.status(201).json({ success: true, data: post });
});
export default router;
// app.js
import postsRouter from "./routes/posts.js";
app.use("/api/posts", postsRouter);
Middleware is just a function with three arguments
A logging middleware, an auth check, a rate limiter - they're all the same shape: a function that receives the request, the response, and a way to hand off to whatever comes next.
function requestLogger(req, res, next) {
console.log(`${req.method} ${req.originalUrl}`);
next();
}
app.use(requestLogger);
One error handler at the end, not scattered try/catches everywhere
Express lets you define a single error-handling middleware with four arguments. Wrap your route logic and pass caught errors to next(err) instead of repeating the same try/catch boilerplate in every route.
app.use((err, req, res, next) => {
console.error(err);
res.status(err.status || 500).json({
success: false,
message: err.message || "Internal server error",
});
});Comments
Loading comments...
Related Articles
Taming Slow MongoDB Aggregation Pipelines in Production
An aggregation pipeline that returns instantly on your 500-document local dataset can crawl once it hits a few million real documents. Here's how to actually find and fix the stage that's costing you.
Read ArticleBuilding a Sliding-Window Rate Limiter for Node.js APIs with Redis
Fixed-window rate limiting looks fine in a demo and then lets through double the traffic right at the window boundary. Here's the sliding-window-counter approach that fixes that, built directly on Redis.
Read ArticleMulti-Tenant Data Isolation: Shared Schema vs Separate Databases
Every multi-tenant SaaS eventually has to answer one question honestly: how do you stop one customer from ever seeing another customer's data? Here's how the three common isolation strategies actually compare in practice.
Read Article