Why HTTP Status Codes Matter

Every time your browser loads a page, submits a form, or your code calls an API, the server responds with a three-digit number before it sends any data back. That number is the HTTP status code, and it is the server's way of telling you exactly what happened with your request. Did it succeed? Did the resource move? Was there an authentication problem? Did something crash?

For frontend developers, understanding status codes means building better error handling and user experiences. For backend developers, choosing the right status code makes your API predictable and self-documenting. For anyone debugging a production incident at 2 AM, knowing the difference between a 502 and a 504 can save you thirty minutes of looking in the wrong place.

You do not need to memorize all 63 officially registered status codes. But there is a core set of roughly 20 that you will encounter constantly, and understanding them deeply will make you a more effective developer.

The 5 Classes at a Glance

HTTP status codes are grouped into five classes based on their first digit. Before diving into individual codes, it helps to understand what each class represents:

Class Range Meaning When You See It
1xx 100–199 Informational Rare. The server acknowledges the request and asks the client to continue. You almost never handle these directly.
2xx 200–299 Success The request was received, understood, and accepted. This is what you want to see.
3xx 300–399 Redirection The client must take additional action to complete the request, usually following a new URL.
4xx 400–499 Client Error Something is wrong with the request itself. The client needs to fix something before retrying.
5xx 500–599 Server Error The server failed to fulfill a valid request. The problem is on the server side.

The most important takeaway from this classification: 4xx means the client did something wrong, and 5xx means the server did something wrong. Getting this distinction right in your own APIs is critical for debugging. If your API returns a 500 when the user sends malformed JSON, you are making every future debugging session harder than it needs to be.

The 2xx Codes You Use Daily

200 OK is the workhorse of the web. It means the request succeeded and the server is returning the requested data. For a GET request, the response body contains the resource. For a POST request, it contains the result of the action. When in doubt, 200 is the default success response.

GET /api/users/42 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 42,
  "name": "Ada Lovelace",
  "email": "[email protected]"
}

201 Created is more specific. It tells the client that the request succeeded and a new resource was created as a result. This is the correct response for a successful POST that creates a record. Good APIs also include a Location header pointing to the newly created resource:

POST /api/users HTTP/1.1
Content-Type: application/json

{ "name": "Grace Hopper", "email": "[email protected]" }

HTTP/1.1 201 Created
Location: /api/users/43
Content-Type: application/json

{
  "id": 43,
  "name": "Grace Hopper",
  "email": "[email protected]"
}

204 No Content means the request succeeded but there is intentionally no response body. This is the standard response for a successful DELETE request, or a PUT/PATCH that does not need to return the updated resource. It tells the client "it worked, and there is nothing more to say."

DELETE /api/users/43 HTTP/1.1

HTTP/1.1 204 No Content

A common mistake in REST API design is returning 200 with an empty body when 204 is more semantically correct. The distinction matters for client code: with 204, the client knows not to attempt parsing a response body.

3xx Redirects — Permanent vs Temporary

Redirects tell the client that the resource they requested is available at a different URL. The nuances between redirect codes matter enormously for SEO and for APIs that need to preserve the HTTP method during a redirect.

301 Moved Permanently is the most important redirect for SEO. It tells browsers and search engines that the resource has permanently moved to the URL specified in the Location header. Search engines will transfer ranking authority (link equity) from the old URL to the new one. Browsers will cache this redirect aggressively.

GET /old-page HTTP/1.1

HTTP/1.1 301 Moved Permanently
Location: /new-page

302 Found indicates a temporary redirect. The original URL should remain in search engine indexes because the move is not permanent. Use this for A/B tests, maintenance pages, or geo-based redirects where the original URL is still the canonical one.

Here is where it gets tricky. Both 301 and 302 have a historical problem: many browsers change the HTTP method from POST to GET when following the redirect, even though the spec says they should not. This is a disaster for API clients that POST data and then get redirected.

307 Temporary Redirect and 308 Permanent Redirect were introduced to solve this problem. They work exactly like 302 and 301 respectively, but they guarantee the HTTP method is preserved. If a client sends a POST and gets a 307, it must POST again to the new URL, not GET.

Code Duration Preserves Method? Best For
301 Permanent No (may change to GET) SEO, moving web pages
302 Temporary No (may change to GET) Temporary web page redirects
307 Temporary Yes API temporary redirects
308 Permanent Yes API permanent redirects

The practical rule: for web pages, use 301 and 302. For APIs, prefer 308 and 307.

4xx Client Errors — The Common Culprits

400 Bad Request is the generic "you sent something the server cannot process." This covers malformed JSON, missing required fields, invalid data types, or any request that violates the expected format. When returning a 400, always include a descriptive error message in the response body so the client knows what to fix:

POST /api/users HTTP/1.1
Content-Type: application/json

{ "name": "", "email": "not-an-email" }

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "Validation failed",
  "details": [
    { "field": "name", "message": "Name is required" },
    { "field": "email", "message": "Invalid email format" }
  ]
}

401 Unauthorized vs 403 Forbidden is one of the most commonly confused pairs in HTTP. Despite its name, 401 is really about authentication, not authorization. It means "I don't know who you are — please provide valid credentials." The response should include a WWW-Authenticate header indicating the expected authentication scheme.

403 Forbidden means "I know who you are, but you are not allowed to do this." The server understood the request and verified the client's identity, but the client lacks the necessary permissions. A regular user trying to access an admin endpoint gets a 403, not a 401.

404 Not Found needs little introduction. The resource does not exist at the requested URL. In REST APIs, this is the correct response when a specific entity is not found, such as GET /api/users/99999 when user 99999 does not exist. Some APIs also return 404 for entire endpoint paths that are not recognized.

409 Conflict indicates that the request conflicts with the current state of the resource. Common scenarios include trying to create a user with an email that already exists, or attempting to update a resource that has been modified by another client since you last read it (optimistic locking). This is more specific than 400 and tells the client exactly what kind of problem occurred.

422 Unprocessable Entity (originally from WebDAV, now widely adopted) means the server understands the request format and the JSON is valid, but the content is semantically wrong. The distinction from 400 is subtle: 400 means the request is malformed (bad syntax), while 422 means the request is well-formed but the data does not make sense (e.g., setting an end date before a start date). Many APIs use 400 for both cases, and that is acceptable too.

429 Too Many Requests is the rate limiting response. When a client sends too many requests in a given time window, the server responds with 429 and typically includes a Retry-After header telling the client how long to wait:

HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711843200

{
  "error": "Rate limit exceeded",
  "message": "You have exceeded 100 requests per minute. Try again in 60 seconds."
}

5xx Server Errors

When you see a 5xx, the problem is on your side (if you are the server) or your provider's side (if you are the client). These codes are your first clue during infrastructure debugging.

500 Internal Server Error is the catch-all for unexpected server failures. An unhandled exception, a null pointer, a database query that throws — anything the server did not anticipate. When you see 500s in production, check your application logs first. The response body should never include stack traces or internal details in production, as this exposes implementation details to attackers.

502 Bad Gateway means a server acting as a reverse proxy or gateway received an invalid response from the upstream server. In a typical deployment, Nginx sits in front of your application. If your Node.js or Python app crashes, Nginx cannot get a valid response from it, so it returns 502 to the client. When you see a 502:

503 Service Unavailable means the server is temporarily unable to handle the request, usually due to being overloaded or undergoing maintenance. Unlike 500, a 503 implies the condition is temporary and the client should try again later. Servers should include a Retry-After header when possible. This is the correct status code to return during planned deployments or when your application starts rejecting requests under heavy load.

504 Gateway Timeout is similar to 502 but specifically means the upstream server did not respond within the allowed time. When you see 504s, the upstream application is running but taking too long to respond. Investigate:

The key distinction: 502 means the upstream gave a bad response (or no response because it crashed), while 504 means the upstream did not respond in time. This narrows your debugging immediately.

The Unofficial Codes Worth Knowing

Not every status code you encounter in the wild is in the official IANA registry. Some were created as jokes, others by specific platforms, but a few have become so widely recognized that they are worth knowing.

418 I'm a Teapot was defined in RFC 2324 as part of the Hyper Text Coffee Pot Control Protocol, an April Fools' Day joke from 1998. The server refuses to brew coffee because it is, permanently, a teapot. Despite being a joke, it was implemented in Node.js, Google, and many other systems. It has become a symbol of internet humor and is often used in development as a test response or Easter egg. In 2017, a campaign to remove it from Node.js was famously rejected.

420 Enhance Your Calm was used by the old Twitter API (v1) as a rate limiting response before 429 was standardized in RFC 6585 (2012). If you are maintaining legacy integrations with older APIs, you might still encounter it. In modern APIs, always use 429 instead.

451 Unavailable For Legal Reasons is a more recent addition that became an official standard in RFC 7725 (2015). Named after Ray Bradbury's novel Fahrenheit 451, it indicates that a resource is unavailable due to legal demands such as government censorship or DMCA takedowns. Some ISPs and content platforms use it when content is blocked in specific jurisdictions. Unlike a 403, it specifically communicates that the restriction is legal rather than technical.

While these codes are fun trivia, the practical takeaway is this: if you see an unfamiliar status code in a response, check whether it is a platform-specific extension before assuming it is a bug. Cloudflare, AWS, and other infrastructure providers have their own unofficial codes (like Cloudflare's 520-527 range) that carry specific diagnostic meaning within their ecosystems.

Look Up Any Status Code

Instantly search and decode any HTTP status code with our free reference tool.

Open HTTP Status Code Lookup

Frequently Asked Questions

What is the difference between a 401 and a 403 status code?
A 401 Unauthorized means the request lacks valid authentication credentials — the server does not know who you are. A 403 Forbidden means the server knows who you are but you do not have permission to access the resource. In short, 401 is an identity problem and 403 is a permissions problem.
When should I use 301 vs 302 redirects?
Use a 301 Moved Permanently when the resource has permanently moved to a new URL and you want search engines to update their index. Use a 302 Found when the redirect is temporary and the original URL should remain indexed. For REST APIs, prefer 307 and 308 as they guarantee the HTTP method is preserved during the redirect.
What does a 502 Bad Gateway error mean?
A 502 Bad Gateway means a server acting as a gateway or proxy received an invalid response from an upstream server. This typically happens when a reverse proxy like Nginx cannot reach the application server behind it, often because the application has crashed, is still starting up, or the upstream connection timed out.
What is the difference between 200 and 201 status codes?
200 OK is a general success response indicating the request was processed successfully. 201 Created is a more specific success code indicating that the request resulted in a new resource being created. You should return 201 after a successful POST request that creates a new record, along with a Location header pointing to the new resource.
How should I handle rate limiting in my API?
Return a 429 Too Many Requests status code when a client exceeds your rate limit. Include a Retry-After header indicating how many seconds the client should wait before retrying. Good APIs also include headers like X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset to help clients manage their request volume proactively.