Which HTTP methods are idempotent?
Idempotent methods are those that can be safely retried.
Junior Level
Idempotent methods are those that can be safely retried.
Idempotent methods:
| Method | Idempotent | Why |
|---|---|---|
| GET | Yes | Only reads data, changes nothing |
| HEAD | Yes | Like GET, but without response body |
| OPTIONS | Yes | Returns information about supported methods |
| PUT | Yes | Full resource replacement. Retry = same result |
| DELETE | Yes | First deletes, subsequent calls confirm absence |
Non-idempotent methods:
| Method | Idempotent | Why |
|---|---|---|
| POST | No | Each call may create a new resource |
| PATCH | Depends | Depends on what exactly PATCH does |
Examples:
GET /users/1 — idempotent (read)
PUT /users/1 — idempotent (replace)
DELETE /users/1 — idempotent (delete)
POST /users — NOT idempotent (create)
// GET is idempotent because it only reads.
// PUT is idempotent because it replaces (replaced once — replaced again with the same thing).
// POST is not idempotent because it adds (added once — added again = two objects).
Middle Level
Safe methods: GET, HEAD, OPTIONS
They are idempotent by definition, since they should not change state.
Important: Caching servers (Varnish, Cloudflare) may aggressively cache these methods. If you make GET non-idempotent (e.g., increments a counter), the cache will “hide” the changes.
State-changing idempotent methods: PUT, DELETE
- PUT: Full replacement. If you set
status = 'ACTIVE'ten times, the status remains'ACTIVE' - DELETE: Deletion. First call deletes, rest confirm absence
Why is POST not idempotent?
POST is typically used for adding to a collection. 5 requests POST /orders will create 5 orders. Due to POST’s non-idempotency, it cannot be automatically retried on network timeout — this leads to the “double payment” problem.
PATCH: “Depends on implementation”
{"op": "replace", "path": "/age", "value": 30}— idempotent{"op": "add", "path": "/tags", "value": "new"}— not idempotent (on retry, another tag will be added)
// `replace` always sets the same value — retry is harmless.
// `add` adds an element to a collection — each retry adds another one.
Diagnostics
- 412 Precondition Failed: Used with
If-Matchto guarantee idempotency ofPUT/PATCH - Always make two identical DELETE calls in a row when testing an API
Senior Level
RFC 9110 and Infrastructure Contract
Idempotency is a contract between server and client, fixed in the RFC 9110 specification. At the Senior level, it’s important to understand how this contract affects infrastructure behavior (proxies, caches, Service Mesh).
Role in Service Mesh
Modern systems use Service Mesh (Istio, Linkerd) with Automatic Retries:
- If an endpoint is marked as idempotent — the mesh automatically retries the request on 503 or TCP Timeout
- If you make a mistake and
POSTis automatically retried — you get duplicate data in the DB
// Service Mesh (Istio) by default only retries GET, PUT, DELETE.
// POST requires explicit annotation (e.g., retryOn: retriable-4xx).
Performance and Optimization
Idempotency Budget
In high-load systems, retries can cause a “request storm” (Retry Storm). If the system is struggling and thousands of clients start retrying idempotent requests — it won’t recover.
Solution: Exponential Backoff and Jitter on retries, even for idempotent methods.
Edge Cases
Post-Incremental IDs
If PUT /users/1 generates related records (audit log with new IDs) — this is not a violation of idempotency. Idempotency concerns the primary resource. Internal technical IDs or system logs don’t break the contract.
Monitoring
- Metric:
http_requests_retry_total: Spike in retries for non-idempotent methods — signals a critical error - Service Mesh configuration must clearly distinguish idempotent and non-idempotent endpoints
Interview Cheat Sheet
Must know:
- Idempotent: GET, HEAD, OPTIONS, PUT, DELETE
- Non-idempotent: POST (usually), PATCH (depends on implementation)
- Safe methods (GET, HEAD, OPTIONS) are idempotent by definition — they don’t change state
- PUT is idempotent: full resource replacement yields the same result on retry
- DELETE is idempotent: after first deletion the resource is gone, subsequent calls confirm absence
- PATCH is idempotent only with deterministic operations (replace — yes, add — no)
- Service Mesh (Istio) automatically retries only idempotent requests on 503
- For POST with Idempotency Key in Service Mesh, explicit retryOn annotation is needed
Frequent follow-up questions:
- Why can’t POST be automatically retried? — Risk of data duplication (double payments, orders)
- How does Service Mesh use idempotency? — Automatically retries GET/PUT/DELETE on 503, POST — only with explicit configuration
- What is a Retry Storm? — Retry storm: when a system goes down, thousands of clients simultaneously retry requests
- Why doesn’t DELETE idempotency break when generating audit logs? — Idempotency concerns the primary resource, not side effects
Red flags (DO NOT say):
- “All HTTP methods are idempotent” — POST is definitely not idempotent
- “DELETE is not idempotent because the second time it returns 404” — server state is the same, this is idempotent
- “PATCH is always non-idempotent” — replace operations are idempotent
- “Idempotency is about response codes” — it’s about server state
Related topics:
- [[What is idempotency]]
- [[Why GET and DELETE are idempotent]]
- [[Is POST idempotent]]
- [[What are the main HTTP methods used in REST]]
- [[What is the difference between PUT and PATCH]]