PUT vs PATCH: Which HTTP Method Should You Use for REST API Updates?
The Problem
I’ve seen this mistake countless times: a developer wants to update a single field in a resource, so they send a PUT request with just that field. The result? All other fields get deleted. The resource is partially destroyed.
Original resource:{ "name": "gizmo", "category": "widgets", "color": "blue", "price": 10}
Developer sends PUT with just price change:PUT /products/10{ "price": 12 }
Result: Entire resource replaced with just { "price": 12 }- name, category, color all goneThis happens because PUT replaces the entire resource. The developer confused PUT with PATCH. Both methods update resources, but they work fundamentally differently. Using the wrong method causes data loss or retry failures.
The Solution
PUT: Complete Replacement
PUT replaces the entire resource with the submitted data. Think of it as “overwrite” mode.
PUT https://api.contoso.com/products/10Content-Type: application/json
{ "name": "gizmo", "category": "widgets", "color": "blue", "price": 12}When you use PUT:
1. Sends complete resource representation2. Idempotent: multiple identical requests produce same result3. Server replaces entire resource with submitted data4. Fields omitted in request get removed from resourceIdempotency is the key property here. If a network timeout occurs and you retry the exact same PUT request five times, the resource ends up in the same state as if you sent it once. This makes PUT safe for automatic retries.
Request 1: PUT /products/10 { price: 12 } - Network timeout, client retries
Request 2: PUT /products/10 { price: 12 } - Network timeout, client retries
Request 3: PUT /products/10 { price: 12 } - Success: Resource now has price: 12
Final state: Same as if only one request succeededPATCH: Partial Update
PATCH modifies only the fields you specify. The rest of the resource stays untouched.
PATCH https://api.contoso.com/products/10Content-Type: application/merge-patch+json
{ "price": 12}Result:
Original:{ "name": "gizmo", "category": "widgets", "color": "blue", "price": 10}
After PATCH with { "price": 12 }:{ "name": "gizmo", // unchanged "category": "widgets", // unchanged "color": "blue", // unchanged "price": 12 // updated}PATCH is more efficient for small changes. When a resource has 50 fields and you only need to update one, PATCH sends just that one field instead of all 50.
Two PATCH Formats
PATCH supports two JSON formats. Choose based on complexity:
JSON Merge Patch (RFC 7396) - Simple, intuitive:
PATCH https://api.contoso.com/products/10Content-Type: application/merge-patch+json
{ "price": 12, // Update price "color": null, // Delete color field "size": "small" // Add new field}- Same structure as original resource- Include only fields to change- Use null to delete a field- Warning: null in original data means deleteJSON Patch (RFC 6902) - Operations-based, more control:
PATCH https://api.contoso.com/products/10Content-Type: application/json-patch+json
[ {"op": "replace", "path": "/price", "value": 12}, {"op": "remove", "path": "/color"}, {"op": "add", "path": "/size", "value": "small"}, {"op": "test", "path": "/name", "value": "gizmo"}]op: "add" - Add value at pathop: "remove" - Remove value at pathop: "replace" - Replace value at pathop: "copy" - Copy from one path to anotherop: "move" - Move from one path to anotherop: "test" - Validate value matches before proceedingJSON Patch gives you explicit operations and a “test” operation for validation. Use it when you need conditional updates or complex operations.
Comparison Table
Property | PUT | PATCH------------------|------------------------|------------------------Scope | Entire resource | Specified fields onlyIdempotent | Yes | Not guaranteedOmitted fields | Deleted | UnchangedBandwidth | Full resource | Only changesStatus codes | 200, 201, 204, 409 | 200, 400, 409, 415Use case | Replace everything | Modify specific fieldsWhy This Matters
The choice affects both bandwidth and reliability:
Large resource with 100 fields, updating 1 field:
PUT: Sends all 100 fields (~10KB)PATCH: Sends 1 field (~100 bytes)
For mobile clients or slow networks, PATCH wins.Network failure scenario:
PUT: Safe to retry automatically (idempotent)PATCH: Retry may cause different result (not idempotent)
Example of non-idempotent PATCH:PATCH /counter with { "value": "increment" }- First request: counter becomes 11- Retry request: counter becomes 12- Different result each timeFor automatic retry mechanisms (like HTTP client libraries), PUT is safer. For PATCH, you need manual retry logic that understands the patch format.
Common Mistakes
I’ve seen these mistakes in production code:
Mistake 1: Using PUT to “update a field”
PUT https://api.contoso.com/products/10Content-Type: application/json
{ "price": 12}
# Result: All other fields deleted. Disaster.PATCH https://api.contoso.com/products/10Content-Type: application/merge-patch+json
{ "price": 12}
# Result: Only price updated. Other fields preserved.Mistake 2: Treating PATCH as idempotent
PATCH https://api.contoso.com/orders/10Content-Type: application/merge-patch+json
{ "status": "processing"}
# If the server auto-increments a "version" field on each update,# repeated requests produce different results.# Not idempotent!Mistake 3: JSON Merge Patch with null values
Original resource:{ "name": "product", "color": null // Explicit null, means no color}
Developer wants to set color to "red":PATCH with { "color": "red" } -- Works fine
Developer wants to keep color as null:PATCH with { "color": null } -- This DELETES the color field!
JSON Merge Patch interprets null as "delete this field"When your resource legitimately contains null values, use JSON Patch instead:
PATCH https://api.contoso.com/products/10Content-Type: application/json-patch+json
[ {"op": "replace", "path": "/color", "value": null}]
# Explicitly sets color to null, doesn't delete the fieldMistake 4: Missing Content-Type header
PATCH https://api.contoso.com/products/10
{ "price": 12}
# Server doesn't know the patch format# May reject or misinterpretPATCH https://api.contoso.com/products/10Content-Type: application/merge-patch+json
{ "price": 12}For JSON Merge Patch, use application/merge-patch+json. For JSON Patch, use application/json-patch+json.
Summary
In this post, I explained the key differences between PUT and PATCH for REST API updates. PUT replaces the entire resource and is idempotent, making it safe for automatic retries. PATCH modifies only specified fields and is not guaranteed idempotent, making it efficient for partial updates.
Use PUT when you have the complete resource data and need idempotent behavior. Use PATCH when you only need to modify specific fields without affecting the rest of the resource. Remember that PUT deletes omitted fields while PATCH preserves them.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments