204 No Content
The server fulfilled the request successfully but has no response body to return.
Quick Reference
| Category | 2xx Success |
|---|---|
| RFC | RFC 9110, Section 15.3.5 |
| Has body | No — a 204 response MUST NOT include a message body |
| Cacheable | Yes — default cacheable by the shared cache rules |
| Typical use | PUT/DELETE/PATCH success; autosave; OPTIONS preflight; heartbeat pings |
What 204 No Content Means
HTTP 204 No Content tells the client that the server processed the request successfully and that the client does not need to navigate away from the current page or update its view. RFC 9110 specifies that the response MUST NOT include a message body. A 204 with a body is a protocol violation; conforming clients will discard any content they receive after the headers.
The key distinction from 200 OK is intent. A 200 response body contains a representation of the resource — JSON, HTML, whatever was requested. A 204 response signals success without providing any representation. The client already has what it needs, or does not need anything back.
The key distinction from 200 OK is intent. Use 204 when the operation succeeded and the response body would be empty or irrelevant. Use 200 when you have something meaningful to return. Returning 200 {} where 204 belongs is not wrong, but it forces clients to parse an empty JSON object and obscures intent.
Common Use Cases
DELETE Operations
Deleting a resource has no natural response body. After a successful DELETE the resource no longer exists, so there is nothing to return. 204 is the conventional response:
DELETE /api/posts/42 HTTP/1.1
HTTP/1.1 204 No Content
Alternatives exist — some APIs return 200 with a confirmation payload like {"deleted": true, "id": 42} — but 204 is idiomatic and wastes no bandwidth.
PUT / PATCH Updates
When a client sends the full updated resource in the request body, the server already knows what the resource looks like after the update. Echoing it back in the response is redundant. 204 is appropriate here:
PUT /api/users/7 HTTP/1.1
Content-Type: application/json
{"name": "Ced", "email": "ced@example.com"}
HTTP/1.1 204 No Content
If the server modifies the resource beyond what the client sent (generating timestamps, computed fields, etc.) then returning 200 with the updated representation is more useful. The client otherwise needs a follow-up GET to see the final state.
Autosave and Ping Endpoints
Autosave systems send frequent PATCH or POST requests as the user types. The client does not need a response body — it just needs to confirm the save succeeded. 204 minimises payload size across potentially hundreds of requests per session.
// Client: autosave every 5 seconds
async function autosave(draft) {
const res = await fetch('/api/drafts/current', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(draft)
});
if (res.status === 204) {
updateSavedIndicator();
}
}
CORS Preflight (OPTIONS)
Browsers send an OPTIONS request before cross-origin requests to check whether the server allows the method and headers the actual request will use. The correct response is 204 (or 200) with the appropriate Access-Control-Allow-* headers and no body:
OPTIONS /api/data HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 86400
Returning 204 in Common Frameworks
Express.js
app.delete('/api/items/:id', async (req, res) => {
await Item.findByIdAndDelete(req.params.id);
res.sendStatus(204); // sends 204 with no body
});
Django REST Framework
from rest_framework.response import Response
from rest_framework import status
class ItemView(APIView):
def delete(self, request, pk):
item = get_object_or_404(Item, pk=pk)
item.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
FastAPI
from fastapi import Response
@app.delete("/items/{item_id}", status_code=204)
async def delete_item(item_id: int, response: Response):
await db.delete_item(item_id)
# Return None — FastAPI sends 204 with no body
Go net/http
func deleteHandler(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
if err := store.Delete(id); err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
w.WriteHeader(http.StatusNoContent)
}
Headers That Still Apply with 204
Although 204 carries no body, several headers remain meaningful:
- ETag — a successful PUT that returns 204 can include an ETag of the new resource state, letting the client update its cached copy without a follow-up GET.
- Cache-Control — 204 is cacheable by default. A
Cache-Control: no-storeorCache-Control: no-cacheheader overrides this for the method involved. - Location — unusual on a 204 but valid if the operation created or redirected to a resource.
Browser Behavior
When a browser form submits to an endpoint and receives 204, the browser does not navigate away — the page stays exactly as it is. This is intentional: 204 means “you don’t need to do anything with this response.” Compare to 200, which causes browsers to render the response body, or 3xx, which triggers a navigation. For AJAX calls (fetch, XMLHttpRequest), 204 is handled normally — the promise resolves, res.ok is true, and res.body is null or empty.
204 vs Related Status Codes
| Code | Has body | Typical use |
|---|---|---|
| 200 OK | Yes | Success with representation (GET response, POST with result) |
| 201 Created | Usually | Resource created; body is the new resource or a Location header |
| 204 No Content | No | Success without representation (DELETE, autosave, OPTIONS preflight) |
| 205 Reset Content | No | Success; client should reset the form or UI element that made the request |
| 304 Not Modified | No | Conditional GET; cached copy is still valid |
Frequently Asked Questions
Can I return 204 for a POST request?
Yes, when the POST performs an action rather than creating a resource. Submitting a form that triggers a side effect (send email, enqueue a job, record a vote) can return 204 if there is no resource to return. If the POST creates a resource, 201 with a Location header is more appropriate.
What happens if I accidentally return a body with 204?
RFC 9110 says the server MUST NOT include a message body with 204. If one is included, HTTP/1.1 clients are supposed to discard it. In practice, behavior is inconsistent — some clients may log a warning, others silently discard the body. Avoid including a body.
Why not just return 200 with an empty body?
You can, and many APIs do. The reason to prefer 204 is semantic clarity: 200 implies a body is present or expected, and an empty body may be treated as an error by some clients or proxies. 204 explicitly communicates “no body is coming, that is intentional.”
Does 204 prevent the browser from navigating?
Yes, for form submissions. A browser form that receives 204 stays on the current page. This is the same behavior as return false in older JavaScript, but handled at the HTTP level. For fetch/XHR calls, the promise simply resolves with an empty response.