Quick lookup with explanations
{{ c.name }}
HTTP status codes are three-digit numbers returned by the server in every response to a client. They were first introduced in 1991 with HTTP/0.9, standardized in RFC 2616 (1999), and later consolidated in RFC 7231 (2014) and the current RFC 9110 (2022). The status code is part of the Status-Line of an HTTP response (e.g. HTTP/1.1 200 OK) and tells the client whether the request succeeded, was redirected, or failed. Without these codes, a browser would not know whether to render an HTML page, follow a redirect, or display an error.
The first digit of the status code identifies the class; the second and third digits identify the specific outcome:
These codes show up daily in developer work — in browser DevTools network tab, API responses, and server logs:
If-None-Match/If-Modified-Since; body is empty, browser uses its cache.WWW-Authenticate header should follow.Retry-After header indicates the wait time.Both codes redirect the browser to another URL; the difference lies in permanence and therefore SEO behavior. A 301 signals "this URL no longer exists — use the new address permanently". Google transfers full PageRank to the destination, browsers cache the redirect aggressively (often for months). A 302 means "just redirect this one request, the old URL remains the master". Search engines keep the original in the index and re-check every request. Rule of thumb: for domain migrations, URL restructuring, or permanent slug changes, ALWAYS use 301. For A/B tests, maintenance redirects, or the "after successful POST go to summary" flow, 302 (or better 303 / 307) is correct. A common mistake: using 302 instead of 301 during site migrations — Google then loses the link equity.
HTTP caching is one of the most important performance optimizations on the web — and status codes play a central role. The most important caching code is 304 Not Modified: the browser sends an If-None-Match header with the last stored ETag, the server checks whether the resource has changed, and replies with 304 and an empty body if not — the browser uses its local copy. This saves bandwidth dramatically. 200 OK with Cache-Control: max-age=31536000, immutable won't be re-requested for a year. 301 is often cached by browsers for months — be careful when switching from 301 back to 302! 503 with Retry-After tells CDNs when a retry makes sense. Header combinations like Cache-Control, ETag, Last-Modified and Vary determine actual cache behavior.
REST APIs use status codes systematically: 200 for read resources, 201 after successful POST with a Location header, 204 for DELETE without body, 400 for validation errors, 401 for missing auth token, 404 for nonexistent resources, 422 when the data is valid JSON but violates business rules. Browser debugging: the DevTools network tab's status column immediately shows where problems are — red 4xx/5xx rows are the first thing to check. Server configuration (Nginx, Apache, Caddy) uses status codes for rewrite rules, error pages, and health checks. SEO migrations live or die by correct 301 redirects: map old URLs to new ones, update sitemap.xml, use Search Console Change-of-Address. Monitoring tools like Uptime Robot poll for 2xx and alert on 5xx.
For a permanent move — new URL structure, domain change, deleted post with a new equivalent — use 301 Moved Permanently. For short-lived redirects (maintenance, A/B test, temporary campaign) use 302 Found or, if the HTTP method must be strictly preserved, 307 Temporary Redirect. For SEO the choice is critical: 301 transfers PageRank, 302 does not.
200 OK with an empty body is technically allowed — but clients usually expect content. 204 No Content is the clean choice when the server intentionally sends no body (e.g. after a successful PUT or DELETE). The key difference: 204 must not have a body per RFC 9110, while 200 is expected to have one. APIs should consistently use 204 for no-content responses — it saves bandwidth and makes the semantics clear.
The rule of thumb is simple: 401 Unauthorized means "you're not logged in — please authenticate". 403 Forbidden means "you're logged in, but you don't have permission for this action". Example: an unauthenticated user calls /admin → 401. A logged-in regular user calls /admin → 403. On 401, the server should return a WWW-Authenticate header indicating the expected auth scheme (e.g. Bearer, Basic).
Yes — providers and frameworks have established their own codes. Famous: 418 I'm a teapot from RFC 2324 (April Fools' but actually implemented). Cloudflare uses 520 (Web Server Returned an Unknown Error), 521 (Web Server is Down), 522 (Connection Timed Out), 523 (Origin Is Unreachable), 524 (A Timeout Occurred), 525/526 (SSL issues). Microsoft IIS has 440 (Login Timeout), AWS has 460/463/464. Nginx uses 444 (No Response — closes the connection without responding). These aren't in the RFC but are common in practice and usually classified in the 4xx/5xx ranges.
An HTTP status code is part of the status line returned by the server in every response: HTTP/1.1 200 OK. The three-digit number is machine-readable; the reason phrase ("OK", "Not Found") is for humans only and has been explicitly deprecated since RFC 7230 — clients must not parse it. HTTP/2 and HTTP/3 drop the reason phrase entirely, leaving only the number in the :status pseudo-header. Practical consequence: if your proxy or Lua script depends on the reason phrase, you are breaking the HTTP spec.
The first digit classifies the response and is intentionally coarse: 1xx means "hold on, I'm thinking" (Informational), 2xx "everything's fine" (Success), 3xx "look elsewhere" (Redirection), 4xx "your fault" (Client Error), 5xx "my fault" (Server Error). This classification lets clients handle unknown codes sensibly: a 299 is treated like 200, a 599 like 500. That mechanism allows IANA-registered extensions like 451 (Unavailable For Legal Reasons, RFC 7725) to be added without a client update. The official IANA registry lists all accepted codes; custom 6xx or x99 codes violate the spec and break strict reverse proxies like nginx.
Idempotency and cacheability are tied directly to the status code. By default browsers and proxies only cache responses with 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501 — a 200 without explicit Cache-Control can be heuristically stored for hours. With 301 (Moved Permanently) the browser often caches the redirect permanently, which creates nasty behaviour if you want to undo the redirect later — use 302 or 307 if you are not 100% certain. RFC 7231 specifies which methods stay idempotent under which codes: a 405 on POST tells the client the method is generally forbidden, a 409 on PUT tells them the concrete resource state conflicts.
Each of the five classes has semantic guarantees you should respect when designing APIs.
100 Continue for Expect: 100-continue, 101 for WebSocket upgrade, 103 Early Hints allows preload hints before the final response.200 default, 201 after POST with a new resource URL in the Location header, 204 without body (e.g. DELETE), 206 only for range requests.301/308 permanent, 302/307 temporary, 303 for POST-redirect-GET (PRG pattern), 304 only as response to If-Modified-Since/If-None-Match.400 generic error, 401 = not authenticated (login missing), 403 = authenticated but not authorized, 422 for syntactically parsed but semantically invalid data.500 catch-all, 502 upstream replied with garbage, 503 server knows its own limits (maintenance, overload), 504 upstream did not reply in time. Clients should honour Retry-After headers on 503.How to map real-world API situations to the right code — this mirrors what GitHub, Stripe and AWS do in production.
/orders succeeded → 201 Created with Location: /orders/42. Stripe uses this for every resource creation./users/me without a bearer token → 401 Unauthorized with WWW-Authenticate: Bearer. With a valid token but no admin role → 403 Forbidden./articles/5 with stale If-Match ETag → 412 Precondition Failed. Solves the classic "lost update" problem without locking.204 No Content (idempotent) or 410 Gone if the deletion is part of the public API contract and won't come back.429 Too Many Requests with Retry-After: 30 and X-RateLimit-Remaining: 0. GitHub and Twitter do exactly this.Many APIs confuse 401 with 403: 401 means "I don't know who you are" (no login or expired token), 403 means "I know who you are but you still can't". Returning 403 for both blocks legitimate token-refresh logic in the client. Another classic: a 200 with {"error": "..."} in the JSON body. This breaks monitoring tools like Datadog APM or Sentry, which filter by HTTP status — broken requests then look like successes. Equally tricky: 307 and 308 preserve the HTTP method on redirect (POST stays POST), 301 and 302 historically allowed rewriting to GET — many clients still do, causing surprising data loss. For login endpoints reached via POST, always use 303 See Other to make the PRG pattern explicit. Last trap: Cloudflare returns its own 52x codes (520-527) that are not IANA-registered and only indicate Cloudflare-specific edge problems — never reuse them in your own API.
401 Unauthorized means the server could not authenticate the user — either the Authorization header is missing or the token is invalid. 403 Forbidden means the user is known but does not have permission for the action. On 401 the client should trigger login or token refresh, on 403 that makes no sense.400 Bad Request is for requests that fail at the syntactic level — broken JSON, missing headers, wrong Content-Type. 422 Unprocessable Entity (WebDAV, RFC 4918, but de-facto standard for REST) is for syntactically correct bodies whose values violate validation rules — email without @, negative prices, missing required fields. Rails and Laravel use 422 as the default for validation errors.401 Unauthorized with a specific WWW-Authenticate header: WWW-Authenticate: Bearer error="invalid_token", error_description="The access token expired" per RFC 6750. The client then knows a refresh is the right next step instead of forcing a full re-login.type, title, status, detail.418 comes from the April-fools RFC 2324 (Hyper Text Coffee Pot Control Protocol) and is officially reserved: a server told to brew coffee while it is in fact a teapot should return 418. In practice, some APIs (e.g. Cloudflare's mock for scraping bots) use it as an Easter egg. Do not use it in real production APIs.301 Moved Permanently passes PageRank to the new URL and is the standard for permanent domain or path moves. 302 Found keeps PageRank on the old URL and is meant for temporary redirects (e.g. A/B tests or geo-targeted detours). Google treats 308 (permanent, method-preserving) and 307 (temporary, method-preserving) the same as 301/302 for SEO purposes since 2018.