<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/protobuf-tip-1-field-names-are-forever-buf-qeedalbca" -->

---
title: Protobuf Tip #1: Field names are forever · Buf | daily.dev
description: Renaming Protobuf fields is nearly always a bad idea despite the wire format relying on field tags rather than names. Generated code (like Go accessors) breaks...
canonical: https://daily.dev/posts/protobuf-tip-1-field-names-are-forever-buf-qeedalbca
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Protobuf Tip #1: Field names are forever · Buf | daily.dev
og:description: Renaming Protobuf fields is nearly always a bad idea despite the wire format relying on field tags rather than names. Generated code (like Go accessors) breaks...
og:url: https://daily.dev/posts/protobuf-tip-1-field-names-are-forever-buf-qeedalbca
og:image: https://api.daily.dev/og/posts/qeEdALbca.png
og:image:alt: Protobuf Tip #1: Field names are forever · Buf
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Protobuf Tip #1: Field names are forever · Buf

**[Buf Blog](https://daily.dev/sources/buf)** · 4 min read · 0 upvotes · 0 comments

## Summary

Renaming Protobuf fields is nearly always a bad idea despite the wire format relying on field tags rather than names. Generated code (like Go accessors) breaks for downstream consumers, JSON serialization breaks because it does rely on names, and reflection-based tooling can silently misbehave. Even the json_name option doesn't fully solve this because most runtimes accept both the old and new names. When semantics genuinely change (e.g. splitting a currency-specific field into a generic one), the recommended approach is to add new fields side-by-side, deprecate the old one, and reserve its number and name if eventually deleted rather than renaming in place.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://buf.build/blog/totw-1-field-names>

## Questions this post answers

### Does renaming a field in a protobuf message break the wire format?

No, the binary wire format uses field tag numbers, not names, so renaming a field does not change wire serialization. However, it still breaks generated code accessors (e.g., a Go field named FirstName becomes GivenName), breaks JSON serialization since JSON relies on field names, and can break reflection-based tooling that inspects field names.

_Anyone debugging protobuf compatibility issues can find practical breakage scenarios like this on daily.dev._

### Does the json_name option in protobuf fully prevent breakage when renaming a field?

No, using [json_name = "..."] only partially mitigates breakage. Many protobuf runtimes accept both the original field name and the json_name value during deserialization, but once a field is renamed, the old original name is no longer accepted, so a rename with json_name still constitutes a breaking protocol change for JSON consumers.

_Developers weighing protobuf schema changes track gotchas like this on daily.dev before shipping._

### What is the safe way to change a protobuf field's semantics, like removing an implicit currency from a cost field?

Instead of renaming cost_usd to a generic cost field, add new cost and currency fields side-by-side the original, have readers check for cost_usd first and treat its presence as implying currency is USD, then mark cost_usd as deprecated. Only delete cost_usd if you control every reader and writer, and reserve its field number and name to prevent accidental reuse.

_Teams planning protobuf schema migrations reference patterns like this on daily.dev before making the change._

## Similar posts on daily.dev

- [Better than JSON](https://daily.dev/posts/better-than-json-d2je9kyed) · Hacker News · 250 upvotes · 22 comments
- [The modern Protobuf workflow · Buf](https://daily.dev/posts/the-modern-protobuf-workflow-buf-c2m7gywhe) · Buf Blog · 1 upvotes · 0 comments
- [Packing Binary Is Fun, Actually](https://daily.dev/posts/packing-binary-is-fun-actually-mjoiqneoh) · Programming Digest · 0 upvotes · 0 comments
- [Protobuf-ES just got a lot faster · Buf](https://daily.dev/posts/protobuf-es-just-got-a-lot-faster-buf-rcovndatq) · Buf Blog · 18 upvotes · 1 comments

---

Tags: [#architecture](https://daily.dev/tags/architecture), [#backend](https://daily.dev/tags/backend), [#database](https://daily.dev/tags/database)

[View this post on daily.dev](https://daily.dev/posts/protobuf-tip-1-field-names-are-forever-buf-qeedalbca)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Protobuf Tip #1: Field names are forever · Buf","url":"https://daily.dev/posts/protobuf-tip-1-field-names-are-forever-buf-qeedalbca","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/protobuf-tip-1-field-names-are-forever-buf-qeedalbca"},"datePublished":"2026-08-23T07:20:10.100Z","dateModified":"2026-10-14T02:36:08.595Z","description":"Renaming Protobuf fields is nearly always a bad idea despite the wire format relying on field tags rather than names. Generated code (like Go accessors) breaks...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/65fe43777608a51d200aafa483eab536?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/65fe43777608a51d200aafa483eab536?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Buf Blog","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Buf Blog","logo":"https://media.daily.dev/image/upload/s--2YBgo_Nm--/f_auto,q_auto/v1787469605/logos/buf?_a=BAMAMicg0","url":"https://daily.dev/sources/buf"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/protobuf-tip-1-field-names-are-forever-buf-qeedalbca","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"architecture,backend,database","timeRequired":"PT4M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Buf Blog","item":"https://daily.dev/sources/buf"},{"@type":"ListItem","position":3,"name":"Protobuf Tip #1: Field names are forever · Buf"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/protobuf-tip-1-field-names-are-forever-buf-qeedalbca#faq","mainEntity":[{"@type":"Question","name":"Does renaming a field in a protobuf message break the wire format?","acceptedAnswer":{"@type":"Answer","text":"No, the binary wire format uses field tag numbers, not names, so renaming a field does not change wire serialization. However, it still breaks generated code accessors (e.g., a Go field named FirstName becomes GivenName), breaks JSON serialization since JSON relies on field names, and can break reflection-based tooling that inspects field names. Anyone debugging protobuf compatibility issues can find practical breakage scenarios like this on daily.dev."}},{"@type":"Question","name":"Does the json_name option in protobuf fully prevent breakage when renaming a field?","acceptedAnswer":{"@type":"Answer","text":"No, using [json_name = \"...\"] only partially mitigates breakage. Many protobuf runtimes accept both the original field name and the json_name value during deserialization, but once a field is renamed, the old original name is no longer accepted, so a rename with json_name still constitutes a breaking protocol change for JSON consumers. Developers weighing protobuf schema changes track gotchas like this on daily.dev before shipping."}},{"@type":"Question","name":"What is the safe way to change a protobuf field's semantics, like removing an implicit currency from a cost field?","acceptedAnswer":{"@type":"Answer","text":"Instead of renaming cost_usd to a generic cost field, add new cost and currency fields side-by-side the original, have readers check for cost_usd first and treat its presence as implying currency is USD, then mark cost_usd as deprecated. Only delete cost_usd if you control every reader and writer, and reserve its field number and name to prevent accidental reuse. Teams planning protobuf schema migrations reference patterns like this on daily.dev before making the change."}}]}
```

