HTTP Status Codes: The Complete Developer Reference
Stop guessing what status code to return. Use this guide.
2xx — Success
Code
Name
When to Use
200
OK
Successful GET, PUT, DELETE, or PATCH
201
Created
Resource successfully created. Include Location header
202
Accepted
Request accepted but not yet processed (async operations)
204
No Content
Successful DELETE or PUT where no body is needed
// 200 — Standard successres.status(200).json({data:user});// 201 — Resource createdres.status(201).json({data:newUser}).location('/api/users/123');// 202 — Async task startedres.status(202).json({jobId:'abc123',status:'pending',checkUrl:'/api/jobs/abc123'});// 204 — Deleted successfullyres.status(204).send();// No body!
3xx — Redirection
Code
Name
When to Use
301
Moved Permanently
Resource permanently moved to new URL
302
Found
Temporary redirect (old, use 303 or 307 instead)
304
Not Modified
Client's cached version is still valid
// 301 — SEO-friendly permanent redirectres.redirect(301,'/new-url');// 304 — Let browser use cache (handled by ETag/Last-Modified)app.get('/api/data',(req,res)=>{constetag=computeEtag(data);if (req.headers['if-none-match']===etag){returnres.status(304).send();// No body needed}res.set('ETag',etag).json({data});});
4xx — Client Errors
Code
Name
When to Use
400
Bad Request
Malformed request syntax
401
Unauthorized
Missing or invalid authentication
403
Forbidden
Authenticated but not authorized for this resource
404
Not Found
Resource doesn't exist
405
Method Not Allowed
Route exists but wrong HTTP method
409
Conflict
Request conflicts with current state
415
Unsupported Media Type
Wrong Content-Type header
422
Unprocessable Entity
Valid syntax but semantic errors (validation failed)
429
Too Many Requests
Rate limit exceeded
// 400 — Bad request bodyif (!req.body.email){returnres.status(400).json({error:'Missing required field: email'});}// 401 — Not authenticatedif (!req.headers.authorization){returnres.status(401).json({error:'Authentication required'});}// 403 — Authenticated but forbiddenif (req.user.role!=='admin'){returnres.status(403).json({error:'Admin access required'});}// 404 — Resource not foundconstuser=awaitUser.findById(id);if (!user)returnres.status(404).json({error:'User not found'});// 405 — Wrong methodapp.all('/api/users',(req,res)=>{res.set('Allow','GET, POST').status(405).json({error:'Method not allowed'});});// 409 — Duplicate resourceconstexisting=awaitUser.findByEmail(email);if (existing)returnres.status(409).json({error:'Email already registered'});// 422 — Validation failedconsterrors=validateUser(req.body);if (errors){returnres.status(422).json({error:'Validation failed',details:errors});}// 429 — Rate limitedres.set('Retry-After','60').status(429).json({error:'Too many requests'});
5xx — Server Errors
Code
Name
When to Use
500
Internal Server Error
Unhandled server error
502
Bad Gateway
Upstream server returned invalid response
503
Service Unavailable
Server is overloaded or in maintenance
504
Gateway Timeout
Upstream server took too long
// 500 — Catch-all (don't expose details in production!)app.use((err,req,res,_next)=>{constisDev=process.env.NODE_ENV!=='production';res.status(500).json({error:{message:isDev?err.message:'Internal server error',...(isDev&&{stack:err.stack}),}});});// 503 — Maintenance modeapp.use((req,res,_next)=>{if (isMaintenanceMode){returnres.status(503).json({error:'Service temporarily unavailable',retryAfter:300});}next();});
The Decision Tree
Did the request succeed?
├── YES → 2xx
│ ├── Created something? → 201
│ ├── Processing async? → 202
│ ├── Deleted something? → 204
│ └── Otherwise → 200
│
└── NO → Why?
├── Client's fault → 4xx
│ ├── No auth? → 401
│ ├── Not allowed? → 403
│ ├── Not found? → 404
│ ├── Bad input? → 400 or 422
│ ├── Duplicate? → 409
│ ├── Too many? → 429
│ └── Other → 400
│
└── Server's fault → 5xx
├── Upstream down? → 502
├── Upstream slow? → 504
├── Overloaded? → 503
└── Unknown → 500
Common Mistakes
// ❌ Using 200 for errorsres.status(200).json({error:'User not found'});// Client can't distinguish success from failure by status code!// ❌ Using 404 for everythingres.status(404).json({error:'Method not allowed'});// Use 405 for wrong methods!// ❌ Using 500 for client errorsres.status(500).json({error:'Missing email'});// Use 400!// ❌ Returning errors with 200res.json({success:false,error:'Something'});// Always set the correct status code!// ✅ Correct approachif (!user)returnres.status(404).json({error:{code:'NOT_FOUND',message:'User not found'}});
Quick Reference
Category
Codes
Success
200, 201, 202, 204
Redirect
301, 302, 304
Client Error
400, 401, 403, 404, 405, 409, 415, 422, 429
Server Error
500, 502, 503, 504
What status code do you see misused most often?
Follow @armorbreak for more API development content.
Top comments (0)
Subscribe
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Top comments (0)