What is the difference between HTTP status 404 Not Found and 410 Gone, and when is each the right choice?
answer
- 404 = no current representation, says nothing about time
- 410 = existed, permanently gone, stop asking
- Unknown permanence → use 404
- 410 needs a tombstone to know it existed
- 410 speeds de-indexing; 301 for moved
basics
~20 s404 says the server found no current representation and gives no promise about the past or future — the resource may appear later. 410 says the resource existed, is intentionally and permanently gone, and clients and crawlers should stop asking and remove links.
solid answer
~60 s**404 Not Found** means the origin server did not find a current representation for the target and is not saying whether the condition is temporary or permanent. It is deliberately non-committal: a typo'd URL, a not-yet-created resource, or a resource you are hiding all map to 404. **410 Gone** is the stronger claim: the resource *was* available, its removal is believed **permanent**, and the server has no forwarding address. RFC 9110 frames 410 as a courtesy to link maintainers — it invites clients to delete cached references. Search engines act on it: a 410 typically causes faster de-indexing than a repeated 404. Use 410 when you deliberately retire content — a deleted account's public profile, a sunset API version, a purged GDPR record — **and** you can cheaply prove the id once existed (tombstone row or id-range rule). Use 404 as the default, including for hiding resources the caller may not see, because 410 would confirm the id was real. Both are cacheable by default under RFC 9111 heuristics; 410 is the one you actually want cached.
code
http · 8 linesGET /v1/orders/42 HTTP/1.1
Host: api.example.com
HTTP/1.1 410 Gone
Content-Type: application/json
Cache-Control: max-age=86400
{"code":"API_VERSION_RETIRED","message":"v1 was retired on 2026-01-31; use /v2/orders"}go deeper
Give the plain contrast: 404 = not found, no statement about the future; 410 = existed and is permanently removed.
Add that unknown permanence means 404, that both are cacheable, and that crawlers de-index faster on 410.
Discuss the tombstone cost, eventual-consistency false 410s, API sunsetting with 410 plus Sunset headers, and consistency with a hide-existence-via-404 policy.
Frame it as lifecycle policy: how identifiers are retired platform-wide, what retention the tombstones carry under erasure obligations, and how clients and crawlers are meant to react.
## The semantic difference Both codes say "there is nothing here for you", but they differ in the **claim about time**. - **404 Not Found**: the server found no current representation for the target resource and *is not disclosing* whether this is temporary or permanent. RFC 9110 explicitly notes that a 404 does not indicate whether the condition is permanent, and that a server may use 404 instead of 403 when it does not wish to reveal why a request was refused. - **410 Gone**: the target resource is **no longer available at the origin server** and the condition is **likely permanent**. If permanence is unknown, the spec says use 404 instead. So 410 carries information 404 withholds: *it existed, it is intentionally gone, stop asking.* ## Who actually behaves differently Because both are 4xx and cacheable by default (RFC 9111 lists 404 and 410 among heuristically cacheable statuses), the practical differences are behavioural rather than protocol-mechanical: - **Search crawlers**: a 410 is treated as a definite removal signal and generally drops the URL from the index faster than repeated 404s, which crawlers keep re-checking for a while in case the page returns. - **Link checkers and feed readers**: many treat 410 as "prune this link", 404 as "maybe retry later". - **API clients and SDKs**: a 410 is a good signal to stop polling a resource or to purge a locally cached copy, whereas 404 might just mean "not created yet" in an eventually consistent system. ## When 410 earns its keep - **Sunsetting an API version or endpoint**: after the announced date, `/v1/*` returns 410 with a body pointing at v2. This is a much clearer operational signal than a 404, and it pairs naturally with the `Sunset` and `Deprecation` headers during the warning window. - **Deliberately purged content**: a deleted user profile, a taken-down listing, an expired campaign page, a record erased under a right-to-erasure request. "It existed and will not come back" is exactly 410. - **Retired identifiers**: when you keep a tombstone row after a hard delete, 410 costs you nothing and gives callers precise information. ## When 404 is the right default - **You cannot tell whether the id ever existed.** After a hard delete with no tombstone, the server literally cannot distinguish "deleted" from "never existed" — 404 is the truthful answer, and claiming 410 would be a guess. - **Eventual consistency.** A resource created a moment ago on another node may legitimately 404 now and 200 shortly after. A 410 would be a lie and could make a well-behaved client give up permanently. - **Hiding existence.** When you return 404 for a resource that exists but the caller may not see (in place of 403), returning 410 for the deleted ones re-opens the oracle: an attacker learns which ids were real. If you adopt the hide-with-404 policy for a resource family, do not sprinkle 410s through it. ## Costs of 410 you should name To answer 410 you must remember that the id existed — a tombstone table, a soft-delete flag, or an id-allocation rule. Tombstones grow forever unless pruned, and under a data-erasure obligation the tombstone itself must contain no personal data. That is the real design tradeoff behind the code, and it is the part interviewers are usually probing. ## Neighbours and common mistakes - **301 Moved Permanently** is the right answer when content *moved* rather than vanished; 410 says there is no forwarding address. - **204 No Content** means the request succeeded and there is simply no body — never use it to mean "missing". - **403** confirms existence; that is the whole reason people substitute 404. - Returning **404 for a wrong HTTP method** on an existing path is wrong: that is 405, and it must carry an `Allow` header. - Serving a soft-404 (HTTP 200 with an "oops, not found" page) is a genuine bug: crawlers index it and monitoring cannot see the failure.
- Your service hard-deletes rows with no tombstone. A client asks for a deleted id. Which code do you return?404. The server genuinely cannot distinguish "deleted" from "never existed", and RFC 9110 says to prefer 404 when permanence is unknown. Returning 410 would be a guess, and in a system with hidden or not-yet-replicated resources it can push clients to stop retrying something that is actually reachable.
- How do 404 and 410 interact with caching?Both are heuristically cacheable under RFC 9111, so an intermediary may reuse them even without explicit freshness headers. That is desirable for 410, where you often add an explicit `Cache-Control: max-age=...` to keep crawlers and clients away, but risky for 404 on a resource that will soon exist — there, send `Cache-Control: no-store` or a very short max-age.
saying these in an interview costs you the question
- Claiming 404 means the resource never existed — it makes no such claim
- Using 410 when the system cannot actually prove the id existed
- Returning 410 for temporarily unavailable content instead of 404 or 503
- Returning 404 when the path exists but the method is unsupported (that is 405)
- Serving HTTP 200 with a "not found" page (soft 404)