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
Up to 2 MB Β· nothing uploaded
Paste or drop a schema to explore it.
{{ errorCount }} problem{{ errorCount === 1 ? '' : 's' }} found
Valid, with {{ warnCount }} thing{{ warnCount === 1 ? '' : 's' }} worth checking
Schema is valid
No problems found. {{ summaryLine }}
{{ summaryLine }}
- line {{ d.line }}, col {{ d.col }} β {{ d.path }} β {{ d.message }}
- {{ r.label }} {{ r.type }} {{ r.tag }} {{ r.doc }}
Nothing to show.
{{ m.name }}{{ m.kind }}
{{ m.doc }}
| {{ h }} |
|---|
| {{ cell }} |
No records or messages with fields.
-
{{ t.kind }}
{{ t.fullName }}{{ t.detail }}
No named types.
Unresolved references
{{ unresolvedNote }}
-
?
{{ u.type }}used by {{ u.field }}
Well-known types used
-
{{ w.name }}{{ w.note }} JSON: {{ w.json }}.
{{ fingerprints.canonical }}
Documentation, aliases, defaults and whitespace are removed and names are fully qualified, so two schemas that read data identically produce identical text here. Field order is kept, because it decides the binary layout.
| Fingerprint | Value |
|---|---|
| Rabin 64 (hex) | {{ fingerprints.rabin64Hex }} |
| Rabin 64 (unsigned) | {{ fingerprints.rabin64Unsigned }} |
| Rabin 64 (signed) | {{ fingerprints.rabin64Signed }} |
| MD5 | {{ fingerprints.md5 }} |
| SHA-256 | {{ fingerprints.sha256 }} |
The canonical form needs a schema that parses.
File-level features{{ edition }}
Editions replace the syntax keyword with individual features that inherit from the file to each message to each field. The "from" column is the part that is invisible in the source.
| Feature | Value | From |
|---|---|---|
{{ f.name }} | {{ f.value }} | {{ f.from }} |
No feature information β this file uses a syntax declaration rather than an edition.
{{ normalized }}
Printed back from the parsed structure with consistent formatting. Re-parsing this produces the same structure as your input β that equivalence is what the parser is tested against.
Nothing to normalise.
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.
Frequently asked questions
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.