The Humble PATCH That Saved Our Sanity
Let me tell you about the day I fell in love with PATCH requests. It was 2 AM, our user update endpoint was melting under load, and I was staring at logs that showed customers losing profile changes because our PUT implementation required the entire user object. Every partial update was a potential data race. Every mobile client with a spotty connection was rolling the dice on whether their carefully typed bio would survive the round trip.

That’s when I discovered that PATCH isn’t just PUT’s quirky cousin. It’s the difference between replacing your entire engine because the oil light came on and actually changing the oil. Most developers treat PATCH as an afterthought. But after six years of API archaeology, I can tell you it’s one of the most underappreciated tools in the HTTP toolkit.
The beauty of PATCH lies in its surgical precision. While PUT says “here’s the new state of this resource,” PATCH whispers “here’s exactly what needs to change.” This isn’t just semantic sugar. In distributed systems where network partitions happen and clients operate with stale data, the difference between intent and replacement can make or break your software’s reliability.

JSON Merge Patch: The Gateway Drug
If you’ve never implemented PATCH, JSON Merge Patch (RFC 7396) is your entry point. It’s beautifully simple: send only the fields you want to change, and they’ll overwrite the existing values. Want to update a user’s email? Send `{“email”: “new@example.com”}`. The server merges this with the existing resource, leaving everything else untouched.
Here’s where it gets interesting. JSON Merge Patch handles nested objects by replacing entire nested structures, which sounds limiting until you realize how often that’s exactly what you want. When someone updates their address, you probably want to replace the whole address object. You don’t want to worry about whether they’re keeping the old ZIP code with the new street name.
The real magic happens with null values. In JSON Merge Patch, `{“phone”: null}` doesn’t set the phone field to null. It deletes the field entirely. This gives you a clean way to handle optional fields without creating dedicated deletion endpoints. I’ve seen teams build entire field management systems around this simple behavior.
When JSON Merge Patch Hits Its Limits
But JSON Merge Patch shows its age when you need array operations. Try to remove one item from a list of hobbies, and you’re back to sending the entire array. This is where JSON Patch (RFC 6902) flexes its muscles with operations like `{“op”: “remove”, “path”: “/hobbies/2”}`. Suddenly you can add, remove, replace, move, copy, and test individual array elements with surgical precision.
JSON Patch reads like assembly language for JSON manipulation. That’s both its power and its curse. The verbosity that makes it expressive also makes it intimidating. Most teams see the operation arrays and flee back to PUT requests. But here’s the thing: JSON Patch operations are atomic. Either the entire patch succeeds, or none of it does. Try getting that guarantee with multiple PUT requests.
I learned this the hard way during a user preferences migration. We had users with complex notification settings. Arrays of channels, each with nested preferences. JSON Merge Patch would have required rebuilding entire preference trees for simple changes. JSON Patch let us target individual notification types with pinpoint accuracy. When network issues caused retries, the test operations prevented duplicate applications.
The Production Reality Check
Here’s what the tutorials don’t tell you: implementing PATCH properly requires rethinking your validation layer. With PUT, you validate a complete resource. With PATCH, you’re validating partial changes against current state. That innocent-looking email update might violate business rules when combined with the user’s current account type.
The solution is conditional validation. Your PATCH handler needs to reconstruct the post-patch state before running validation rules. This means your validation logic becomes a pure function that takes a complete resource state. Not a framework that assumes it’s working with the entire incoming payload. It’s more work upfront, but it prevents the class of bugs where valid partial updates create invalid final states.
Concurrency control becomes essential with PATCH operations. ETags aren’t just nice-to-have anymore. They’re mandatory. When Client A patches the email while Client B patches the phone number, you need to ensure both changes can coexist or fail fast with a 409 Conflict. I’ve seen production systems where the lack of proper ETag handling turned PATCH into a data corruption vector.
The Patterns That Actually Work
After implementing PATCH across dozens of services, here are the patterns that survive contact with production. First, always support both JSON Merge Patch and targeted field updates in the same endpoint. Use Content-Type headers to distinguish between `application/merge-patch+json` and `application/json`, defaulting to merge semantics for backwards compatibility.
Second, implement optimistic locking from day one. Your PATCH endpoint should require an If-Match header with the current ETag and return the new ETag in the response. Yes, it means clients need to track ETags. But it also means you can sleep at night knowing concurrent updates won’t silently overwrite each other.
Finally, make your PATCH responses include the complete updated resource, not just a success indicator. Clients operating with partial local state need to see the full picture after their changes apply. This turns PATCH from a fire-and-forget operation into a state synchronization primitive. Which is what most client code actually needs.
The next time you’re designing an update endpoint, resist the urge to default to PUT. PATCH forces you to think about change as an intentional operation rather than wholesale replacement. That mindset shift ripples through your entire API design. Give it a try on your next feature. Your mobile developers will thank you, your database will thank you, and your 3 AM self will definitely thank you.