Skip to content

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.

The Common Mistake
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 gone

This 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 Request
PUT https://api.contoso.com/products/10
Content-Type: application/json
{
"name": "gizmo",
"category": "widgets",
"color": "blue",
"price": 12
}

When you use PUT:

PUT Characteristics
1. Sends complete resource representation
2. Idempotent: multiple identical requests produce same result
3. Server replaces entire resource with submitted data
4. Fields omitted in request get removed from resource

Idempotency 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.

PUT Idempotency Example
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 succeeded

PATCH: Partial Update

PATCH modifies only the fields you specify. The rest of the resource stays untouched.

PATCH with JSON Merge Patch
PATCH https://api.contoso.com/products/10
Content-Type: application/merge-patch+json
{
"price": 12
}

Result:

PATCH 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:

JSON Merge Patch Format
PATCH https://api.contoso.com/products/10
Content-Type: application/merge-patch+json
{
"price": 12, // Update price
"color": null, // Delete color field
"size": "small" // Add new field
}
JSON Merge Patch Rules
- Same structure as original resource
- Include only fields to change
- Use null to delete a field
- Warning: null in original data means delete

JSON Patch (RFC 6902) - Operations-based, more control:

JSON Patch Format
PATCH https://api.contoso.com/products/10
Content-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"}
]
JSON Patch Operations
op: "add" - Add value at path
op: "remove" - Remove value at path
op: "replace" - Replace value at path
op: "copy" - Copy from one path to another
op: "move" - Move from one path to another
op: "test" - Validate value matches before proceeding

JSON Patch gives you explicit operations and a “test” operation for validation. Use it when you need conditional updates or complex operations.

Comparison Table

PUT vs PATCH Summary
Property | PUT | PATCH
------------------|------------------------|------------------------
Scope | Entire resource | Specified fields only
Idempotent | Yes | Not guaranteed
Omitted fields | Deleted | Unchanged
Bandwidth | Full resource | Only changes
Status codes | 200, 201, 204, 409 | 200, 400, 409, 415
Use case | Replace everything | Modify specific fields

Why This Matters

The choice affects both bandwidth and reliability:

Bandwidth Comparison
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.
Retry Reliability
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 time

For 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”

Wrong: PUT for Partial Update
PUT https://api.contoso.com/products/10
Content-Type: application/json
{
"price": 12
}
# Result: All other fields deleted. Disaster.
Correct: PATCH for Partial Update
PATCH https://api.contoso.com/products/10
Content-Type: application/merge-patch+json
{
"price": 12
}
# Result: Only price updated. Other fields preserved.

Mistake 2: Treating PATCH as idempotent

Non-idempotent PATCH Example
PATCH https://api.contoso.com/orders/10
Content-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

The Null Problem
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:

Correct: JSON Patch for Null Values
PATCH https://api.contoso.com/products/10
Content-Type: application/json-patch+json
[
{"op": "replace", "path": "/color", "value": null}
]
# Explicitly sets color to null, doesn't delete the field

Mistake 4: Missing Content-Type header

Wrong: Missing Content-Type
PATCH https://api.contoso.com/products/10
{
"price": 12
}
# Server doesn't know the patch format
# May reject or misinterpret
Correct: Specify Content-Type
PATCH https://api.contoso.com/products/10
Content-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