Protobuf Schema Viewer

Read a .proto file properly β€” including the things the source does not show you: whether each field tracks presence, which edition feature applies and where it was inherited from, and the JSON name it maps to.

Drop a .proto file here

or or

Up to 2 MB Β· nothing uploaded

{{ inBytes }}
{{ status }}

Paste or drop a schema to explore it.

Your .proto file is tokenized and analysed entirely in your browser. Nothing you paste is ever uploaded to a server.

Field presence: the thing the source does not tell you

Whether a protobuf field can distinguish "unset" from "zero" is not written anywhere in the file — it is inferred from the syntax or edition, the label, whether the field sits in a oneof, and whether its type is a message. A bare singular scalar in proto3 has no presence at all, so 0, "" and false are indistinguishable from absent. Add optional and it gains presence. That single distinction is behind a large share of protobuf bugs, so it gets its own column here with the reason on hover.

Editions, and why the inheritance matters

Editions replace the syntax keyword with individual features — field_presence, enum_type, repeated_field_encoding and others — which can be set at file, message or field level and inherit downwards. The most consequential default change is that edition 2023 makes field presence explicit, the opposite of proto3. Since an override three levels up silently changes how a field behaves, this viewer shows the resolved value and where it came from.

Protobuf JSON is not a mirror of your .proto

The canonical JSON encoding renames fields to lowerCamelCase, writes 64-bit integers as strings rather than numbers, and represents Timestamp and Duration as strings rather than objects. Teams that assume the JSON matches the schema field-for-field discover this during an integration, so the JSON name is shown next to every field.

Imports are honestly reported, not guessed

A .proto that imports another file does not contain those definitions, and no tool can invent them from a single paste. Types defined elsewhere are listed as unresolved, with a note saying whether the file has imports that would plausibly supply them. The google.protobuf well-known types are the exception — they are recognised by name and annotated with their JSON behaviour, without bundling anyone else's schema files.

Working with an Avro schema instead?

Use the Avro Schema Viewer, which validates defaults and logical types and computes canonical fingerprints.

What is field presence, and why does it need a column?

Presence is whether "unset" is distinguishable from "zero". A bare singular scalar in proto3 has no presence, so 0, "" and false all look identical to absent β€” a real source of bugs. Adding the optional keyword, putting the field in a oneof, or using a message type all give it presence instead. None of that is visible from the source unless you already know the rules, which is why it gets its own column here.

Does this support editions?

Yes β€” edition = "2023" and "2024" are parsed, and the resolved feature set is shown per field along with where each value came from: the edition default, a file option, a message option or the field itself. That inheritance chain is exactly what makes an editions file hard to read by eye, so displaying it is the point rather than a nicety.

What changed between proto3 and edition 2023?

The most consequential difference is that field presence defaults to explicit in edition 2023, where proto3 defaults to implicit. Behaviour that used to be tied to the syntax keyword is now controlled by individual features that can be set at file, message or field level, which is more flexible and considerably easier to misread.

Why can it not resolve a type from an imported file?

Because the imported file genuinely is not there. A .proto that imports another file does not contain those definitions, so anything defined elsewhere is reported as unresolved rather than guessed at. Well-known google.protobuf types are the exception: they are recognised by name and annotated, without bundling anyone else's schema files.

What are the JSON names for?

Protobuf's canonical JSON encoding uses lowerCamelCase field names, so user_id becomes userId. It also encodes 64-bit integers as strings, Timestamp and Duration as strings rather than objects, and enums as their symbol names. Those mappings surprise people who assume the JSON mirrors the .proto, so they are shown alongside each field.

Is my .proto uploaded anywhere?

No. Tokenizing and analysis run entirely in your browser. Nothing is transmitted to a server, which matters because a service definition is usually not public.