The packages http-status, http-status-code, http-status-codes, and statuses all provide mappings between HTTP status codes (integers) and their standard text phrases or constants. They solve the problem of avoiding "magic numbers" (like 404 or 500) in code, improving readability and reducing errors. While they share a common goal, they differ significantly in API design, maintenance status, and ecosystem integration. http-status-codes is the most feature-rich and widely adopted community standard, offering bidirectional lookups and extensive constants. statuses is a minimal, low-level utility often used internally by major frameworks like Express and Koa. http-status offers a class-based approach but sees less active evolution. http-status-code is an older, simpler alternative that is largely superseded by more robust options.
http-status-codes, statuses, http-status, and http-status-codeIn professional Node.js development, hardcoding numbers like 404 or 500 is a recipe for confusion. We use libraries to map these integers to human-readable constants like NOT_FOUND or INTERNAL_SERVER_ERROR. While four main packages exist in the npm ecosystemβhttp-status-codes, statuses, http-status, and http-status-codeβthey are not created equal. Some are built for high-level application logic, while others serve as tiny building blocks for frameworks.
This guide breaks down the technical differences, API styles, and real-world trade-offs to help you pick the right tool for your architecture.
The most immediate difference is how these libraries expose data. Do you want named constants to use in your res.status() calls, or just a quick way to turn a number into a string?
http-status-codes is designed for developer experience. It exports a massive object of named constants. This allows for type-safe, self-documenting code where the intent is clear without memorizing numbers.
// http-status-codes
const { StatusCodes } = require('http-status-codes');
// Usage: Clear intent, no magic numbers
res.status(StatusCodes.NOT_FOUND).json({ error: 'Missing' });
res.status(StatusCodes.OK).send('Success');
statuses takes a minimalist approach. It does not export a list of constants for you to import. Instead, it acts as a function that accepts a code and returns the message. It is purely a lookup utility.
// statuses
const status = require('statuses');
// Usage: Get message from code
const message = status(404); // Returns "Not Found"
// It does NOT provide: status.NOT_FOUND constant
http-status uses a class-based or enum-like structure. It groups codes by category (Informational, Success, Redirection, etc.), which can be helpful if you need to logically group checks, though it adds verbosity.
// http-status
const HttpStatus = require('http-status');
// Usage: Access via class properties
res.status(HttpStatus.NOT_FOUND).send('Missing');
// Check category
if (code >= HttpStatus.BAD_REQUEST && code < HttpStatus.INTERNAL_SERVER_ERROR) {
// Handle client errors
}
http-status-code provides a simple mapping object similar to http-status-codes but with a flatter structure and fewer features. It is often used as a direct dictionary.
// http-status-code
const statusCode = require('http-status-code');
// Usage: Direct property access
const code = statusCode['Not Found']; // Returns 404
const message = statusCode[404]; // Returns "Not Found"
Real-world apps often need to convert in both directions: displaying a message to a user based on a code, or determining a code based on a string label.
http-status-codes excels here. It provides dedicated functions for both directions, handling edge cases and custom codes gracefully.
// http-status-codes
const { getStatusText, getStatusCode } = require('http-status-codes');
// Code -> Text
const text = getStatusText(403); // "Forbidden"
// Text -> Code
const code = getStatusCode('Forbidden'); // 403
statuses only supports Code -> Text. If you need the reverse, you must build your own map or use a different library. This keeps the package tiny but shifts the burden to you.
// statuses
const status = require('statuses');
// Code -> Text (Supported)
console.log(status(500)); // "Internal Server Error"
// Text -> Code (Not Supported natively)
// You would need to create a reverse map manually
http-status allows reverse lookups but often requires iterating through its internal structures or using specific helper methods that are less direct than http-status-codes.
// http-status
const HttpStatus = require('http-status');
// Often requires manual lookup or helper usage depending on version
// No simple single-function reverse lookup like getStatusText
const code = HttpStatus['FORBIDDEN'];
http-status-code supports bidirectional access because it exposes the raw mapping object, but it lacks the helper functions that validate input or handle casing inconsistencies.
// http-status-code
const map = require('http-status-code');
// Code -> Text
const text = map[404];
// Text -> Code (Case sensitive and fragile)
const code = map['Not Found'];
Choosing a library isn't just about features; it's about longevity and trust. Is this package still updated? Do major frameworks rely on it?
statuses is the backbone of the Express.js and Koa ecosystems. It is maintained by the Node.js foundation collaborators and is extremely stable. It rarely changes because its job is simple and critical. If you are writing middleware for Express, this is likely already in your dependency tree.
// Used internally by Express/Koa
// Highly stable, low-level dependency
// Best for: Framework authors, minimalists
http-status-codes is the community favorite for application developers. It has frequent updates to include new or obscure HTTP codes and has a very large adoption rate in modern TypeScript and JavaScript projects. It is the safest choice for new startups and enterprise apps alike.
// Community standard for apps
// Active maintenance, rich typescript definitions
// Best for: Application logic, API development
http-status and http-status-code are older packages. While they still work, their update frequency is lower, and they lack the modern TypeScript support and ergonomic features found in http-status-codes. They are perfectly functional but offer less value for new projects.
// Legacy / Stable but less active
// Best for: Maintaining existing codebases using them
// Avoid for: New greenfield projects unless specific features are needed
For most server-side Node.js applications, the performance difference between these libraries is negligible. However, in edge computing (like Cloudflare Workers) or bundled browser environments, every byte counts.
statuses is the undisputed winner for size. It contains only the data needed for standard codes and nothing else. There is no bloat.
// statuses: Minimal footprint
// Ideal for serverless functions where cold start time matters
http-status-codes is larger because it includes extra helper functions, aliases, and a more complex structure to support its rich API. For 99% of backend services, this trade-off is worth the improved developer experience.
// http-status-codes: Larger but feature-rich
// The extra bytes buy you significant DX improvements
| Feature | http-status-codes | statuses | http-status | http-status-code |
|---|---|---|---|---|
| Primary Use | App Development | Framework Internals | Legacy / Specific | Simple Lookup |
| Constants | β
Rich (StatusCodes.OK) | β None | β Class-based | β Basic Object |
| Reverse Lookup | β
getStatusCode() | β No | β οΈ Manual/Complex | β οΈ Direct Access |
| Maintenance | π’ High | π’ High (Core) | π‘ Moderate | π‘ Low |
| Bundle Size | Medium | Tiny | Medium | Small |
For most professional frontend and backend developers, http-status-codes is the clear winner. It strikes the perfect balance between features, maintainability, and ease of use. The ability to write StatusCodes.BAD_GATEWAY instead of 502 makes your code self-documenting and less prone to typos.
Reserve statuses for special cases: if you are building a library yourself, writing high-performance middleware, or strictly optimizing for minimal dependencies. It is a tool for architects, not necessarily for daily application logic.
Avoid starting new projects with http-status or http-status-code unless you have a specific constraint. The ecosystem has moved toward http-status-codes for good reason: it simply makes development faster and safer.
Choose http-status only if you are maintaining a legacy codebase that already relies on its specific class-based structure or if you require its particular set of helper methods for categorizing status codes (e.g., checking if a code is 'informational'). For new greenfield projects, more modern alternatives are generally preferred.
Avoid choosing http-status-code for new projects. It is an older package with limited features and less active maintenance compared to http-status-codes. Unless you are constrained by a specific legacy dependency tree that requires this exact package name, http-status-codes is a superior drop-in replacement with better long-term support.
Choose http-status-codes for most application-level development where you need a rich set of named constants (e.g., StatusCodes.BAD_REQUEST) and bidirectional lookups (code to phrase and vice versa). It is the safest bet for new projects due to its active maintenance, comprehensive coverage of standard and custom codes, and widespread adoption in the community.
Choose statuses if you are building low-level middleware, framework internals, or performance-critical tools where minimal bundle size and zero dependencies are paramount. It provides a simple, fast lookup from code to message but lacks the extensive constant definitions and reverse lookup features of larger libraries.
Utility to interact with HTTP status codes.
Version 2 is a migration of the library to ESM modules and TypeScript. The API remains the same. The build system generates both ESM and CommonJS exports.
For ESM users, the import remains the same.
import status from "http-status";
// Or
import { status } from "http-status";
For CommonJs users, update the require statement.
const { status } = require("http-status");
// Or
const { default: status } = require("http-status");
Once you import or require this module, you may call it with either an HTTP code or a status name. With an HTTP code, you will get the status name while with a status name you will get an HTTP code or some complementary information.
For example, status[418] return IM_A_TEAPOT while status.IM_A_TEAPOT return "I'm a teapot" and status.IM_A_TEAPOT_CODE returns 418.
The package is written in TypeScript and built for CommonJS and ESM.
HTTP code names, information, and classes are respectively accessible with the property {code}_NAME, {code}_MESSAGE and {code}_CLASS. This includes all statuses in the IANA HTTP Status Code Registry, with the only addition being 418 I'm a teapot.
Extra status code are also made available that are not defined in the IANA registry, but used by popular softwares. They are grouped by category. Specific properties are exported by http-status under the property extra followed by the category name. Also, extra codes are merge with regular status codes and made available as modules available inside http-status/lib/{category}.
Available categories are:
unofficialiisnginxcloudflareThey are accessible throught the status.extra[category] property. It is also possible to import one of the category with import status from "http-status/<category>" or const status = require("http-status/
In addition to HTTP status codes, this module also contains status code classes under the classes property. Similar to HTTP codes, you can access class names and messages with the property {class}_NAME and {class}_MESSAGE.
The API is structured as follows:
100
100_NAME
100_MESSAGE
100_CLASS
CONTINUE
101
101_NAME
101_MESSAGE
101_CLASS
SWITCHING_PROTOCOLS
β¦
classes.
βββ 1xx
βββ 1xx_NAME
βββ 1xx_MESSAGE
βββ INFORMATIONAL
βββ 2xx
βββ 2xx_NAME
βββ 2xx_MESSAGE
βββ SUCCESSFUL
βββ β¦
extra.
βββ unofficial.
β βββ 103
β βββ 103_NAME
β βββ 103_MESSAGE
β βββ 103_CLASS
β βββ CHECKPOINT
β βββ β¦
βββ iis.
β βββ 440
β βββ 440_NAME
β βββ 440_MESSAGE
β βββ 440_CLASS
β βββ LOGIN_TIME_OUT
β βββ β¦
βββ nginx.
β βββ 444
β βββ 444_NAME
β βββ 444_MESSAGE
β βββ 444_CLASS
β βββ NO_RESPONSE
β βββ β¦
βββ cloudflare.
β βββ 520
β βββ 520_NAME
β βββ 520_MESSAGE
β βββ 520_CLASS
β βββ UNKNOWN_ERROR
β βββ β¦
For additional information, please refer to original code.
The api example illustrate how to access status names by code and number and how to extra various associated informations.
import status from "http-status";
console.info(status.INTERNAL_SERVER_ERROR);
// Output: 500
console.info(status[500]);
console.info(status[status.INTERNAL_SERVER_ERROR]);
// Both output: "Internal Server Error"
console.info(status["500_NAME"]);
console.info(status[`${status.INTERNAL_SERVER_ERROR}_NAME`]);
// Both output: "INTERNAL_SERVER_ERROR"
console.info(status["500_MESSAGE"]);
console.info(status[`${status.INTERNAL_SERVER_ERROR}_MESSAGE`]);
// Both output: "A generic error message, given when an unexpected condition was encountered and no more specific message is suitable."
console.info(status["500_CLASS"]);
console.info(status[`${status.INTERNAL_SERVER_ERROR}_CLASS`]);
// Both output: "5xx"
classesimport status from "http-status";
const responseCode = status.INTERNAL_SERVER_ERROR;
switch (status[`${responseCode}_CLASS`]) {
case status.classes.INFORMATIONAL:
// The responseCode is 1xx
break;
case status.classes.SUCCESSFUL:
// The responseCode is 2xx
break;
case status.classes.REDIRECTION:
// The responseCode is 3xx
break;
case status.classes.CLIENT_ERROR:
// The responseCode is 4xx
break;
case status.classes.SERVER_ERROR:
// The responseCode is 5xx
break;
default:
// Unknown
break;
}
extra property// Accessing property from the NGINX category
import status from "http-status";
console.info(status.extra.nginx.NO_RESPONSE);
// Accessing default HTTP status merged with NGINX status
import status from "http-status/lib/nginx";
console.info(status.IM_A_TEAPOT);
console.info(status.NO_RESPONSE);
The express example integrate the library with a real wold usage.
import express from "express";
import redis from "redis";
import status from "http-status";
// New Express HTTP server
const app = express.createServer();
// Regster a route
app.get("/", (req, res) => {
const client = redis.createClient();
client.ping((err, msg) => {
if (err) {
return res.send(status.INTERNAL_SERVER_ERROR);
}
res.send(msg, status.OK);
});
});
// Start the HTTP server
app.listen(3000);
The project is sponsored by Adaltas based in Paris, France. Adaltas offers support and consulting on distributed systems, big data and open source.
To automatically generate a new version:
npm run release
Package publication is handled by the CI/CD with GitHub action.