DEVESSENTIALS

HTTP 204 No Content

204 is success without a payload: the server did what was asked and has nothing to add. RFC 9110 says a 204 ends with the header section and can't contain content. On HTTP/1.1 keep-alive connections, stray bytes a buggy server writes after a 204 can corrupt the next response.

2xx · SuccessRFC 9110 §15.3.5

204 No Content

The request succeeded and there is intentionally no content in the response.

Who fixes it: Nobody (success). A success code. Bugs around 204 are usually client code that tries to parse a body that isn't there.

What 204 means

Typical uses are DELETE /items/42, a PUT or PATCH that doesn't echo the resource back, and fire-and-forget endpoints such as analytics beacons. A 204 can still carry headers, e.g. a new ETag after an update.

In a browser, a 204 in response to a form submission or link click means "stay where you are": the current page isn't replaced.

Source: RFC 9110 §15.3.5.

Common problems with 204

  • The client calls await response.json() on a 204 and gets SyntaxError: Unexpected end of JSON input.
  • A handler sets 204 but also writes a JSON body. Express strips it, so clients that relied on the body get nothing.
  • In Next.js, NextResponse.json(data, { status: 204 }) or new Response('', { status: 204 }) throws a TypeError: the Fetch spec forbids any body on a 204, even an empty string. Pass null.
  • An API returns 204 for "no results" on a search or list. An empty list is still content: return 200 with [].
  • A CORS preflight returning 204 is fine and very common. If preflights fail, the problem is the missing Access-Control-Allow-* headers, not the status.

How to send and handle a 204

Express

res.sendStatus(204) sends the status with no body.

app.delete('/api/items/:id', async (req, res) => {
  await db.items.delete(req.params.id);
  res.sendStatus(204); // or res.status(204).end()
});

Next.js Route Handler

The body must be null, not an empty string or JSON.

// app/api/items/[id]/route.ts
export async function DELETE(
  _request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params;
  await deleteItem(id);
  return new Response(null, { status: 204 });
}

Handle it on the client

Only parse JSON when there is a body.

const res = await fetch(url, { method: 'DELETE' });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = res.status === 204 ? null : await res.json();

Check it with curl

-i prints the response headers. A correct 204 has no body and no Content-Length.

curl -i -X DELETE https://api.example.com/items/42

HTTP/2 204
date: Fri, 16 Oct 2026 09:30:00 GMT

Headers that matter with 204

ETag
Send the new version's ETag after an update so the client can keep making conditional requests without a re-fetch.
Content-Length
RFC 9110 §8.6 says a server must not send Content-Length in a 204 response.

204 vs similar status codes

  • 200 OK: Use 200 when you return a body, for example the updated resource after a PATCH.
  • 202 Accepted: Use 202 when a DELETE or update is queued rather than done.
  • 304 Not Modified: Also bodiless, but it's a cache revalidation answer to a conditional GET, not the result of an action.

Related status codes

Looking for another code? Search the full HTTP status codes list, or read which code your API should return in the REST API status codes guide.

Learn more

Browse all developer guides →

Frequently Asked Questions

Can a 204 response have a body?▾

No. RFC 9110 defines 204 as having no content: the response ends after the headers. Express strips any body you write, and the Fetch API throws if you construct a 204 Response with a body. If you need to return data, use 200.

Should DELETE return 204 or 200?▾

204 if there's nothing useful to return, which is the common case. 200 with a body if you want to return the deleted resource or a summary, and 202 if the deletion is queued and not finished yet.

Is a 204 response cacheable?▾

Yes, RFC 9110 lists 204 as heuristically cacheable. In practice it rarely matters, because 204 is mostly a response to DELETE, PUT and POST requests, and caches don't reuse those responses for later GETs.