JSON to Protobuf
Generate a .proto schema from a JSON sample. Field names become snake_case as the style guide requires, field numbers are assigned in order, arrays become repeated, and nested objects become their own messages.
How to generate a protobuf schema from JSON
- Paste a JSON sample — ideally an array of several records, so optional fields are detected.
- Set the Root type name. Nested objects are named after the key that holds them, singularised for arrays.
- Set a Package to namespace the generated code.
- Tick optional to get proto3 explicit presence, so you can tell "absent" from "zero".
- Tick json_name to keep the original JSON spelling in protobuf's JSON mapping.
- Copy the code, or download it as a file.
Field numbers are a contract
Numbers here are assigned 1, 2, 3… in key order, which is fine for a brand-new schema and wrong for an existing one. Field numbers, not names, are what protobuf writes on the wire. Once a message is deployed:
- Never renumber an existing field — old and new binaries will disagree about what the bytes mean.
- Never reuse the number of a deleted field. Mark it
reservedinstead. - Renaming a field is safe on the wire, but breaks JSON mapping unless you set
json_name.
Numbers 1–15 use one byte, so give them to your most frequent fields.
Type mapping
- Integers →
int64. Narrow toint32, or switch tosint64for values that are often negative — zigzag encoding is much smaller there. - Fractional numbers →
double. - Booleans →
bool; strings →string. - Arrays →
repeatedof the element type. - Objects → a separate message.
- null / mixed →
google.protobuf.Value, with the import added automatically.
Getting good types out of a sample
Type inference from a sample is only as good as the sample. Three habits make the output far more useful:
- Paste an array, not one record. When you pass several records, a key missing from any of them is marked optional and a field that is sometimes a number and sometimes a float widens to a float. One record makes everything look required.
- Include the awkward cases. A record with a null, an empty array, and a missing optional key teaches the generator more than ten identical happy-path records.
- Check unions by hand. A field that holds different shapes in different records falls back to the language's "any" type. That is a signal your data has a variant the generator cannot express — model it explicitly.
Privacy
Nothing is uploaded. Inference and code generation run in this tab. No server sees the payload you paste — which matters, because real API responses tend to contain real user data.
FAQ
Does proto3 have nullable fields?
Scalars have no natural null: an unset int64 reads as 0. The optional keyword (restored in protobuf 3.15) adds explicit presence tracking so you can distinguish unset from zero. Wrapper types such as google.protobuf.Int64Value are the older workaround.
Can it generate maps?
No. A JSON object with arbitrary keys is indistinguishable from a fixed-shape message in a sample. If your keys are dynamic, change the field to map<string, T> by hand.
How do I get an Avro schema instead?
Use JSON → Avro — same inference, different target. Avro is the usual choice for Kafka with a schema registry.