JSON to Protobuf / Avro Schema

Generate a proto3 message definition or an Avro record schema from any JSON object.

proto3 .proto message definitionMessage.proto

Paste a real JSON sample and get a starting proto3 message or Avro record schema back, instead of transcribing every field into a blank .proto or .avsc file by hand. Switch formats with one click — the same sample drives both outputs.

  • proto3 .proto message generation with sequential field numbers
  • Avro record schema (.avsc) generation with nullable unions
  • Nested objects become nested message/record types automatically
  • Arrays become repeated fields (Protobuf) or array types (Avro)
  • 100% private — the schema is generated entirely in your browser

Why move from JSON to Protobuf or Avro?

JSON is the easiest format to prototype with — human-readable, no schema compiler, works everywhere. Protobuf and Avro trade that ease for a compact binary wire format and a schema every producer and consumer agrees on ahead of time, which is why they show up once a system needs smaller payloads, faster serialization, or safe schema evolution across services. See JSON vs. Protobuffor the full tradeoff comparison — this tool is the practical next step once you've decided to make the move: paste a real JSON payload and get a starting schema instead of hand-writing one field by field.

Protobuf vs. Avro — Which Should You Generate?

ProtobufAvro
Schema format.proto IDL text, compiled to codeJSON schema (.avsc), often used directly
Needs a code generatorYes — protoc or bufOptional — many Avro libraries read .avsc at runtime
Common ecosystemgRPC services, microservicesKafka, Hadoop, data pipelines
Schema evolution modelNumbered fields — add, don't renumberReader/writer schema resolution
Self-describing on diskNo — needs the .proto to decodeYes — schema can travel with the data

Using a Generated .proto File

protobuf
syntax = "proto3";

package jsonkit;

message Order {
  string order_id = 1;
  int32 user_id = 2;
  double total = 3;
  bool paid = 4;
  repeated Items items = 5;
}

Compile it with protoc (or buf generate) for your target language, then encode/decode against the generated types. Field numbers are assigned in the order fields appear in your sample — review them before shipping, since changing a field number later breaks wire compatibility with anything still using the old numbering.

Field Numbering Rules Worth Knowing

Protobuf field numbers aren't cosmetic — they're what actually gets written on the wire instead of the field name, so they need a few rules respected once a message is in real use:

  • Numbers 1–15 take one byte to encode instead of two — assign them to your most frequently-set fields for a small but free size win.
  • Numbers 19000–19999 are reserved by the Protobuf implementation itself and can't be used.
  • Once a field number ships to production, it can never be reassigned to a different field — mark a removed field's number as reserved instead of reusing it, so an old binary reading new data (or vice versa) can't misinterpret a field.
  • Adding a new field with a new, unused number is always safe and is how Protobuf schemas evolve without breaking older readers or writers.

Using a Generated Avro Schema

Switch the tool to Avro mode and the same sample produces a record schema instead:

json
{
  "type": "record",
  "name": "Order",
  "fields": [
    { "name": "order_id", "type": "string" },
    { "name": "user_id", "type": "long" },
    { "name": "total", "type": "double" },
    { "name": "paid", "type": "boolean" }
  ]
}

Reading data written against it, in Python with fastavro:

python
# pip install fastavro
import fastavro

schema = fastavro.parse_schema(order_schema)  # the JSON above, as a dict

with open("orders.avro", "rb") as f:
    for record in fastavro.reader(f):
        print(record["order_id"], record["total"])

Because Avro's schema is itself JSON, it's directly diffable and reviewable in a normal pull request — a real practical advantage over Protobuf's compiled .proto during schema review.

A Note on Inferred Types

Types are inferred from a single JSON sample, so treat the output as a first draft. A field that was null in your sample becomes a placeholder string (Protobuf) or a nullable ["null", "string"] union (Avro) with a comment or default flagging it — replace it with the real type once you know it. Large integers are emitted as int64/long automatically when a sample value exceeds the 32-bit range.

Frequently Asked Questions

No — this tool only generates the schema text (.proto or .avsc) from your JSON sample. You'll need protoc, buf, or your language's Avro library to actually compile the schema into code or use it for serialization.

Sequentially, starting at 1, in the order fields appear in your JSON sample. Protobuf field numbers must never be reused once a message ships to production, so review and lock these in before you rely on them.

A single JSON sample can't tell you what type a field "should" be when its only observed value is null. Protobuf has no direct null-only primitive, so the tool defaults to string with a comment; Avro gets a ["null", "string"] union. Replace either with the correct underlying type once you know it from your API contract.

Yes — paste a JSON array and the tool uses the first element as the sample to infer the message/record shape, since a repeated top-level array isn't itself representable as a single Protobuf message or Avro record.

No — schema generation runs entirely in your browser using JavaScript. Nothing is uploaded.

Yes, where practical — numbers 1 through 15 encode in one byte instead of two, so putting your most frequently-populated fields in that range is a small, free size optimization. It doesn't affect correctness either way, only wire size.

Yes — unlike Protobuf, most Avro libraries (fastavro in Python, Apache Avro's Java library) can parse and use a .avsc schema directly at runtime with no separate compile step, though generating typed classes ahead of time is also supported if you prefer that workflow.

Related Tools