503 Service Unavailable
Server Error - Server temporarily cannot handle requests
HTTP 503 Service Unavailable
What It Means
The HTTP 503 Service Unavailable status code indicates that the server is currently unable to handle the request due to temporary overloading or maintenance. This is usually a temporary condition.
Common Causes
- Planned maintenance: Server intentionally down for updates
- Traffic spike: More requests than the server can handle
- Resource exhaustion: Out of memory, CPU maxed, connections full
- Deployment in progress: Rolling update temporarily unavailable
- Circuit breaker open: Dependency failed, blocking requests
- Rate limiting: Server protecting itself from overload
Retry-After Header
The 503 response should include a Retry-After header to tell clients when to try again:
HTTP/1.1 503 Service Unavailable
Retry-After: 300
Content-Type: application/json
{
"error": "Service Unavailable",
"message": "Server is under maintenance",
"retry_after": 300
}
Maintenance Mode Implementation
Nginx maintenance page
# Check for maintenance file
if (-f /var/www/maintenance.flag) {
return 503;
}
error_page 503 @maintenance;
location @maintenance {
root /var/www/html;
rewrite ^(.*)$ /maintenance.html break;
add_header Retry-After 3600;
}
Express.js middleware
const maintenanceMode = (req, res, next) => {
if (process.env.MAINTENANCE_MODE === 'true') {
res.set('Retry-After', '3600');
return res.status(503).json({
error: 'Service Unavailable',
message: 'Server is under maintenance'
});
}
next();
};
app.use(maintenanceMode);
503 vs Other 5xx
| Code | Meaning |
|---|---|
| 500 | Something broke (unplanned) |
| 502 | Bad response from upstream |
| 503 | Intentionally unavailable |
| 504 | Upstream took too long |
Client-Side Handling
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url);
if (response.status === 503) {
const retryAfter = response.headers.get('Retry-After');
const delay = retryAfter ? parseInt(retryAfter) * 1000 : 5000;
console.log(`Service unavailable, retrying in ${delay}ms`);
await new Promise(r => setTimeout(r, delay));
continue;
}
return response;
}
throw new Error('Service unavailable after retries');
}
Best Practices
- Always include
Retry-Afterheader - Use friendly maintenance pages for web apps
- Implement graceful shutdown during deployments
- Set up health check endpoints that bypass maintenance mode
- Notify users in advance of planned maintenance