Skip to content
AZ Tools

JSON to Protobuf Schema Converter (proto3)

Turn a JSON object into a proto3 .proto schema with typed fields and nested messages, in your browser.

Protobuf schema

How to use

  1. Paste or type your JSON into the input box.
  2. Optionally rename the root message (defaults to Message).
  3. Copy the generated .proto schema from the output box.

About this tool

Show

Paste any JSON object and get a proto3 schema: a message per nested object, fields renamed to the snake_case that protobuf style expects, and a json_name option emitted wherever the original key would not round-trip. Numbers map to int64 or double, arrays become repeated fields, and a null falls back to google.protobuf.Value since proto has no untyped null. The part to think about before shipping is the field numbers, which are assigned in order here. On the wire a field is identified by its number, never its name, so renaming a field later is free while renumbering one silently breaks every old client. Numbers one to fifteen also encode in a single byte, so they are worth spending on your most frequent fields.

Frequently asked questions

How are numbers typed?

Whole numbers become int64 and numbers with a decimal point become double. Change them to int32, uint32, float and so on if you need a different width.

What happens with null, empty arrays or nested arrays?

These map to google.protobuf.Value (and import "google/protobuf/struct.proto" is added), because proto3 has no native null and doesn't allow repeated repeated fields.

Why do some fields have a json_name option?

Proto field names are lower_snake_case. When the canonical camelCase JSON mapping wouldn't reproduce your original key, a [json_name = "..."] option is added so JSON round-trips correctly.

Is my JSON sent anywhere?

No. Conversion happens entirely in your browser; nothing is uploaded.

Why does my integer come back as a string after a round trip?

That is the proto3 JSON mapping, not a bug in the schema. int64, uint64, sint64 and fixed64 are serialised as JSON strings, because a 64-bit integer does not survive a JavaScript number — 2^53 is the last one that does. So {"id": 5} generated from an int64 field comes back as {"id": "5"}. If your consumers cannot cope with the quotes and your values genuinely fit, change the field to int32 or uint32, which stay as JSON numbers.

The field numbers look arbitrary — do they matter?

They are the only part of the schema the wire format actually carries; names exist purely for your source code. So renaming a field costs nothing and renumbering breaks every message already encoded. Two things follow. Never reuse a number after deleting a field — mark it reserved instead, or an old message will decode into the new field. And numbers 1 to 15 encode their tag in one byte while 16 to 2047 need two, so if a message is large and repeated, put the fields that appear most often in the low numbers. 19000-19999 are reserved by protobuf itself.

Related tools