HTTP Status Codes Cheat Sheet: Every Code Developers Should Know

HTTP status codes are three-digit numbers returned by a server in response to every request. They tell the client whether the request succeeded, failed, or needs further action. Understanding these codes is essential for debugging APIs, building robust error handling, and writing meaningful responses in your own services.

How Status Codes Are Organized

Status codes are grouped into five classes based on the first digit:

1xx — Informational    (request received, continuing)
2xx — Success          (request accepted and processed)
3xx — Redirection      (further action needed)
4xx — Client Error     (problem with the request)
5xx — Server Error     (server failed to fulfill a valid request)
💡 Quick Rule: If it starts with 2, you're good. If it starts with 4, the client messed up. If it starts with 5, the server messed up.

1xx — Informational Responses

These are rarely seen in typical web development but are important in advanced scenarios like WebSocket upgrades and large file uploads.

  • 100 Continue — The server received the request headers and the client should proceed with the body. Used with the Expect: 100-continue header to avoid sending large payloads to a server that will reject them.
  • 101 Switching Protocols — The server is switching to a different protocol as requested by the client. Most commonly seen during WebSocket handshakes (Upgrade: websocket).
  • 103 Early Hints — Allows the server to send preliminary headers (like Link for preloading resources) before the final response. Helps browsers start loading CSS/JS earlier.

2xx — Success

The request was received, understood, and processed successfully.

  • 200 OK — The standard success response. For GET requests, the body contains the resource. For POST, the body contains the result of the action.
  • 201 Created — A new resource was successfully created. Should include a Location header pointing to the new resource. Use this for POST endpoints that create records.
  • 204 No Content — Success, but there's no body to return. Perfect for DELETE endpoints or PUT/PATCH where the client doesn't need the updated resource back.
  • 206 Partial Content — The server is returning only part of the resource, as requested via a Range header. Used for video streaming, resumable downloads, and large file transfers.

Common Mistake: Always Returning 200

// ❌ Bad — everything returns 200
app.post('/users', (req, res) => {
  const user = createUser(req.body);
  res.status(200).json(user);  // Should be 201
});

app.delete('/users/:id', (req, res) => {
  deleteUser(req.params.id);
  res.status(200).json({ message: 'Deleted' });  // Should be 204
});

// ✅ Good — semantic status codes
app.post('/users', (req, res) => {
  const user = createUser(req.body);
  res.status(201).json(user);
});

app.delete('/users/:id', (req, res) => {
  deleteUser(req.params.id);
  res.status(204).send();
});

3xx — Redirection

The client needs to take additional action to complete the request — usually following a different URL.

  • 301 Moved Permanently — The resource has moved to a new URL permanently. Search engines transfer SEO value to the new URL. Browsers cache this redirect aggressively.
  • 302 Found — Temporary redirect. The resource is temporarily at a different URL. Search engines keep indexing the original URL. Browsers don't cache.
  • 304 Not Modified — The resource hasn't changed since the client's cached version. The server sends no body — the client uses its cache. Essential for performance with ETag and If-Modified-Since headers.
  • 307 Temporary Redirect — Like 302, but guarantees the HTTP method and body are preserved. A POST redirect stays a POST. Use 307 over 302 for API redirects.
  • 308 Permanent Redirect — Like 301, but preserves the HTTP method. A POST redirect stays a POST.
⚠️ SEO Note: Use 301 when a page permanently moves (e.g., URL restructuring). Use 302 for temporary situations (e.g., A/B tests, maintenance redirects). Using the wrong one can hurt your search rankings.

4xx — Client Errors

The request was invalid — the client needs to fix something before retrying.

  • 400 Bad Request — The request is malformed or has invalid parameters. Include a clear error message explaining what's wrong.
  • 401 Unauthorized — Authentication is required but was not provided or is invalid. The client should send credentials (API key, JWT, session cookie). Despite the name, this is about authentication, not authorization.
  • 403 Forbidden — The client is authenticated but doesn't have permission to access this resource. This is about authorization. Don't use 404 to hide resources — use 403 when appropriate.
  • 404 Not Found — The resource doesn't exist at this URL. The most familiar HTTP error code. Also used deliberately to hide the existence of resources from unauthorized users.
  • 405 Method Not Allowed — The HTTP method (GET, POST, etc.) is not supported for this endpoint. Should include an Allow header listing valid methods.
  • 409 Conflict — The request conflicts with the current state of the resource. Common for duplicate creation attempts, concurrent edits, or version conflicts.
  • 415 Unsupported Media Type — The server can't process the request's content type. For example, sending XML to an endpoint that only accepts JSON.
  • 422 Unprocessable Entity — The request is well-formed but contains semantic errors (e.g., validation failures). Increasingly preferred over 400 for validation errors in REST APIs.
  • 429 Too Many Requests — Rate limiting. The client has sent too many requests in a given time window. Should include a Retry-After header.

401 vs 403: The Eternal Confusion

// Not logged in at all → 401 Unauthorized
GET /api/admin/users
→ 401 { "error": "Authentication required" }

// Logged in as regular user, trying to access admin endpoint → 403 Forbidden
GET /api/admin/users
Authorization: Bearer <valid-user-token>
→ 403 { "error": "Admin access required" }

// Logged in, resource doesn't exist → 404 Not Found
GET /api/users/99999
Authorization: Bearer <valid-token>
→ 404 { "error": "User not found" }

5xx — Server Errors

The server failed to fulfill a valid request. These indicate bugs, infrastructure issues, or service outages.

  • 500 Internal Server Error — A generic catch-all for unexpected server failures. Usually means an unhandled exception. Log the details server-side; never expose stack traces to clients.
  • 502 Bad Gateway — The server acting as a proxy received an invalid response from the upstream server. Common with reverse proxies (Nginx, load balancers) when the application server crashes or is unreachable.
  • 503 Service Unavailable — The server is temporarily unable to handle requests — usually due to maintenance or overload. Should include a Retry-After header. Many monitoring tools alert specifically on 503s.
  • 504 Gateway Timeout — The proxy server didn't get a response from the upstream server in time. Common when backend processing exceeds the proxy's timeout setting.
💡 Production Tip: Never return raw error messages or stack traces in 5xx responses. Log them internally and return a generic message to the client. For example: { "error": "Something went wrong. Please try again." }

Best Practices for API Status Codes

  • Be specific — Use 201 for creation, 204 for deletion, 409 for conflicts — not 200 for everything.
  • Include error details — The body of 4xx responses should explain what went wrong and how to fix it.
  • Use standard codes — Don't invent custom status codes. Use the response body for application-specific error codes.
  • Be consistent — If you use 422 for validation errors, use it everywhere. Don't mix 400 and 422 for the same type of error.
  • Add Retry-After headers — For 429 (rate limit) and 503 (maintenance) responses, tell clients when to retry.
  • Monitor 5xx rates — Track server error rates in production. A spike in 5xx codes usually means something is broken.

Quick Reference

Code  Name                    When to Use
----- ----------------------- ------------------------------------------
200   OK                      Standard success
201   Created                 Resource created (POST)
204   No Content              Success, no body (DELETE, PUT)
301   Moved Permanently       Permanent URL change
302   Found                   Temporary redirect
304   Not Modified            Cache hit
400   Bad Request             Malformed request
401   Unauthorized            Missing/invalid auth
403   Forbidden               Valid auth, insufficient permissions
404   Not Found               Resource doesn't exist
409   Conflict                Duplicate or version conflict
422   Unprocessable Entity    Validation errors
429   Too Many Requests       Rate limited
500   Internal Server Error   Unhandled server exception
502   Bad Gateway             Upstream server error
503   Service Unavailable     Maintenance or overload
504   Gateway Timeout         Upstream timeout

Building APIs? Format and clean your SQL queries.

Open JSON Formatter →