Why One-Off Update Methods Don’t Scale
Netflix Studio Engineering’s gRPC services model entities like a Production — a film or series with associated schedules and scripts. When a consumer needs to change a detail, say flip format from LIVE_ACTION to HYBRID, the first instinct is to add a dedicated endpoint such as updateProductionFormatRequest. That works for a single field, but Production has many fields. Adding title updates, schedule updates, and so on produces a proliferation of RPCs. Supporting multi-field atomic updates by creating methods for every field combination quickly becomes unmanageable.
An alternative — a single UpdateProduction call that requires the full Production message — has its own problems. Consumers must know and send every required field even if they only want to change one value. And because Production can carry substantial nested data like schedules and scripts, full-object payloads grow large.
Another option is to send only the fields being changed, leaving everything else unset. That works for updates but breaks when you need to null out a field. If a consumer wants to remove the title or a nested value like schedule.planned_launch_date, you’re back to crafting remove-specific RPCs for every nullable field.
FieldMask as the Mutation Contract
The solution Netflix uses is the same FieldMask mechanism covered in Part 1 for reads, applied to mutations. The proto defines an UpdateProductionRequest that carries the data to change plus a FieldMask listing exactly which field paths to act on. Only fields present in the mask are touched; anything else in the payload is ignored.
For example, updating format requires constructing a mask with the format path. The standard utility FieldMaskUtil.fromStringList() builds the mask from a list of paths for a given type. The payload can include other data, but without corresponding mask paths it will not be modified.
Critically, the semantics extend to removals: a field listed in the mask but absent from the payload is interpreted as a request to remove that value. One mask can therefore mix update and remove operations. To change the format while clearing the planned launch date, the mask paths are format and schedule.planned_launch_date, the payload supplies the new format, and the launch date is omitted — the server treats the omission as a deletion.
Empty Mask Means Everything
An unset or empty FieldMask in an update request applies the operation to all fields in the payload. That convention imposes a rule on the caller: without a mask, you must send the entire object. Any field left unset will be removed.
This has a subtle schema-evolution hazard. When a new field like budget is added to the Production message and the update operation type, consumers with stale stubs that don’t send the new field — and also omit the FieldMask — can accidentally null out the budget. Producers who want to prevent this must require a FieldMask on every update, or introduce a versioning scheme that lets the server distinguish old clients and avoid touching fields they don’t know about.
The takeaway, as Netflix’s API team frames it, is that designers should keep operations simple while leaving room to evolve. FieldMask makes a single update RPC capable of precise, atomic changes across both scalar and nested fields — without spawning a new endpoint for every permutation.



