Building a Lightweight API Rate Limiter in Node.js Without External Libraries


Why Rate Limiting Matters
If your API is open to the public, it is vulnerable to abuse. Without any control, malicious users can overwhelm your server, causing downtime or inflated server costs. Rate limiting ensures each client only makes a certain number of requests in a given timeframe.
While most developers reach for packages like express-rate-limit
, there are scenarios where you might want a lightweight, dependency-free solution. This could be for performance, security, or simply to understand what happens under the hood.
Building It From Scratch
Here’s how to implement a simple in-memory rate limiter using only built-in JavaScript objects.
javascriptCopyEdit// rateLimiter.js
const rateLimitWindow = 60000; // 1 minute in ms
const maxRequests = 5; // allowed requests per window
const clients = {}; // store client request timestamps
function rateLimiter(req, res, next) {
const clientIP = req.ip;
const currentTime = Date.now();
if (!clients[clientIP]) {
clients[clientIP] = [];
}
// Filter out timestamps older than the window
clients[clientIP] = clients[clientIP].filter(
timestamp => currentTime - timestamp < rateLimitWindow
);
if (clients[clientIP].length >= maxRequests) {
return res.status(429).json({ message: "Too many requests, try again later." });
}
clients[clientIP].push(currentTime);
next();
}
module.exports = rateLimiter;
Using It in Your Express App
javascriptCopyEditconst express = require("express");
const rateLimiter = require("./rateLimiter");
const app = express();
app.use(rateLimiter);
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(3000, () => console.log("Server running on port 3000"));
Why This Works
In-memory tracking: The
clients
object stores timestamps for each IP, resetting naturally as old timestamps fall outside the time window.No dependencies: Less overhead and reduced attack surface.
Customizable: Change
rateLimitWindow
ormaxRequests
to match your use case.
For production, you might store this in a distributed cache like Redis to handle multiple server instances, but this code is a great starting point for local or small-scale projects.
Subscribe to my newsletter
Read articles from Tobechi Duru directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Tobechi Duru
Tobechi Duru
Software Engineer, MERN-Stack Developer