The Core Difference
Both PUT and PATCH update an existing resource, but they differ in scope:
PUT sends a complete replacement. The server discards the current representation and stores exactly what the client sent. If a field is absent from the PUT body, it is removed from the resource.
PATCH sends a partial update. The server applies only the changes described in the request body, leaving all other fields untouched.
Idempotency
| PUT | PATCH | |
|---|---|---|
| Idempotent by spec | Yes | Not required |
| Safe to retry on network failure | Yes | Depends on implementation |
| Multiple identical requests | Same result | May differ |
PUT is always idempotent: sending PUT /users/42 with the same body ten times leaves the resource in the same state as sending it once.
PATCH idempotency depends on the operation. “Set name to Alice” is idempotent. “Append item to list” is not. Design your PATCH semantics explicitly.
Request Body Comparison
PUT — full resource representation:
PUT /users/42
{
"name": "Alice",
"email": "alice@example.com",
"role": "admin"
}
```text
**PATCH (JSON Merge Patch)** — only changed fields:
```json
PATCH /users/42
{
"email": "newalice@example.com"
}
PATCH (JSON Patch, RFC 6902) — explicit operations:
PATCH /users/42
[
{ "op": "replace", "path": "/email", "value": "newalice@example.com" }
]
When to Use Each
Use PUT when:
- You want full replacement semantics (upload a file, replace a config)
- The client always has the complete resource representation
- You need guaranteed idempotency for safe retries
- You’re creating a resource at a client-specified URL (PUT can create)
Use PATCH when:
- You only want to update specific fields
- The full resource is large and sending it all is wasteful
- You want to avoid accidentally overwriting fields the client didn’t fetch
- You’re building a typical REST API update endpoint
Common Mistakes
Using PUT for partial updates — if a client fetches a user, updates the email, and PUTs the result, any fields added by another client between the fetch and the PUT will be silently overwritten. This is a lost-update race condition. PATCH avoids it.
Assuming PATCH is always safe to retry — unlike PUT, a non-idempotent PATCH (e.g., “add item to cart”) applied twice will produce a different result. Add idempotency keys or use idempotent PATCH semantics if retries are possible.
Forgetting Content-Type for PATCH — JSON Merge Patch should use Content-Type: application/merge-patch+json. JSON Patch uses application/json-patch+json. Using application/json works but loses semantic precision.