Skip to main content

JSON to Protobuf — proto3 Messages, Field Numbers, Zero Upload

JSON to Protobuf — paste JSON, get proto3 message definitions with inferred scalar types, incrementing field numbers, snake_case fields, repeated arrays, and named nested messages.

  • Runs locally
  • Category Developer & DevOps
  • Best for Formatting, validating, shrinking, or inspecting code-adjacent text.
Examples:
How types, field numbers & repeated are inferred

Each JSON object becomes a named message with snake_case fields (the protobuf style guide), each assigned an incrementing field number (1, 2, 3...) in key order — the number, not the name, is the wire identity. Integer numbers infer int64 (JS numbers can overflow int32, so int64 is the safe default); fractional numbers infer double; a number that is sometimes whole and sometimes fractional widens to double. Arrays of objects fold into ONE message and the field becomes repeated; arrays of scalars become repeated <scalar>. A value that is only ever null, or a genuinely mixed array, degrades to google.protobuf.Any (and the matching import is added). Switch to proto2 to emit explicit optional labels, set a package, or toggle proto3 optional for explicit field presence.

What this tool does

Paste any JSON payload — a REST API response, a Kafka event, a config file, an internal record — and get back a Protocol Buffers schema you can save as a `.proto` and feed straight to `protoc`. Each JSON object becomes a named `message` with snake_case fields (the protobuf style guide), and every field is assigned an incrementing field number (`1`, `2`, `3`...) in key order, because protobuf identifies fields by NUMBER on the wire, not by name — renaming `userId` to `user_id` stays lossless. Numbers are split, not flattened: an integer sample infers `int64` (JavaScript numbers overflow `int32`, so `int64` is the safe default), a fractional sample infers `double`, and a field that is sometimes whole and sometimes fractional widens to `double`. Arrays of objects fold into ONE message and the field becomes `repeated`, so `[{"a":1},{"a":1,"b":2}]` gives a single message with both fields — not two near-duplicate types. Arrays of scalars become `repeated <scalar>`, and a nested object lifts out as its own named message (`User.address` → `UserAddress`). A value that is only ever `null`, or a genuinely mixed array, degrades to `google.protobuf.Any` and the matching `import` is added for you. Switch between proto3 and proto2, set a `package`, toggle the proto3 `optional` label for explicit field presence, rename the root message, then copy the output or download the `.proto`. Everything runs in your browser — the JSON never touches a server.

Tool details

Input
Text + Numbers + Structured content
The page exposes text boxes, numeric controls, file pickers, or structured inputs depending on the tool.
Output
Live result + Copy + Download
The result area focuses on usable output, with copy, download, or preview actions when supported.
Privacy
Browser-side processing
The main tool logic does not call an external API, so inputs normally stay in the current tab.
Save / share
Shareable URL state
Key settings are encoded in the URL so another person can reopen the same setup.
Performance budget
Initial JS <= 25 KB
No WASM budget is declared, keeping the tool quick to open on mobile.
Best fit
Developer & DevOps · Developer
Category and role tags drive related tools, internal links, and quick fit checks.

How to use

  1. 1. Input

    Paste or drop your content into the tool panel.

  2. 2. Process

    Click the button. All processing is local in your browser.

  3. 3. Copy / Download

    Copy the result or download to disk in one click.

How JSON to Protobuf fits into your work

Use it in the small gaps between coding, reviewing, debugging, and shipping.

Developer jobs

  • Formatting, validating, shrinking, or inspecting code-adjacent text.
  • Preparing snippets for documentation, tickets, commits, or handoff.
  • Checking a small payload quickly without switching tools.

Developer checks

  • Run irreversible transforms like minify or obfuscate on a copy.
  • Keep secrets out of pasted snippets unless the tool explicitly stays local.
  • Use your normal tests or linter before shipping transformed code.

Good next steps

These links move the current task into a more complete workflow.

  1. 1 JSON to Go Struct JSON to Go struct — paste JSON, get typed structs with json tags, exported fields, nested sub-structs, pointers for nullable, int64 and omitempty options. Open
  2. 2 JSON to Rust Struct JSON to Rust struct — paste JSON, get serde-derived structs with snake_case fields, serde rename, Option for nullable, Vec for arrays, nested sub-structs. Open
  3. 3 JSON to TypeScript Interface JSON to TypeScript interface — paste JSON, get clean interfaces with union types from arrays, optional vs required detection, root name customizable. Open

Real-world use cases

  • Bootstrap a gRPC service contract from an existing JSON API

    You're migrating a REST endpoint to gRPC and need the `.proto` to match what the JSON already returns. Curl the endpoint once, paste the response, name the root `GetUserResponse`, and copy the output into `user.proto`. The nested `address` object lifts out as `GetUserResponseAddress`, the `roles` array becomes `repeated string`, and field numbers are pre-assigned so you can run `protoc` immediately and tune numbers before anything ships.

  • Reverse-engineer a third-party webhook into a typed message

    A vendor sends webhooks as JSON with no schema published. Log a few payloads, paste a representative one, and you get a `message` you can deserialize into instead of poking at `map[string]interface{}`. Where one payload has a field another lacks, the union is captured in one folded message, so a single `.proto` covers the variations you've actually observed.

  • Generate a Kafka / event-bus message definition

    Your team standardised on protobuf for the event bus but the producer still emits JSON during prototyping. Paste a sample event, set the `package` to `events.v1`, and get a clean message with `int64` timestamps and `repeated` item lists. Drop it in the schema registry, and consumers in Go, Java, and Rust all generate matching types from the same `.proto`.

  • Compare proto3 vs proto2 output before committing to a syntax

    You inherited a proto2 codebase and want to see how a new payload looks in both syntaxes. Paste the JSON, flip the syntax toggle, and watch proto2 add explicit `optional` labels while proto3 stays terse. Decide which fits your toolchain, then turn on proto3 `optional` only for the fields where distinguishing "unset" from "zero" actually matters.

  • Document an undocumented internal payload as a schema

    A legacy service passes around a fat JSON blob with no contract. Paste a real example, name the root after the message, and the generated `.proto` becomes living documentation: every field typed, every nested object named, every array marked `repeated`. Check it into the repo so the next engineer reads a schema instead of guessing from `json.loads`.

Common pitfalls

  • Treating the generated field numbers as final. Numbers are assigned in JSON key order, but on the wire the NUMBER is the contract — once shipped you can rename a field freely but never reuse or reorder a number. Review the numbering before production and add `reserved` ranges for fields you plan to add.

  • Expecting int32 / uint32 for small or unsigned IDs. JSON gives no width or sign, so every integer infers as `int64` — the safe superset that holds ms timestamps and snowflake IDs. Narrow to `int32` / `uint32` / `uint64` by hand only when you know the real domain; a JSON `-1` would break an unsigned type.

  • Assuming a single object reveals optional fields. proto3 has no required/optional at the wire level, and a single object has no missing-key signal, so every field is plain singular. To see how optional/union fields fold, paste an array of objects (`[{...},{...}]`) where some elements carry a key and others don't.

  • Pasting JSON5 / JSON-with-comments / trailing commas. We use strict `JSON.parse`, so comments, unquoted keys, and trailing commas all error out. Strip them first, or run the input through a JSON formatter as a pre-step.

Privacy

Your JSON never leaves this browser tab. Parsing and type inference use the browser's built-in `JSON.parse`; there is no network call and no analytics on the textarea content. The Share link encodes your input and option choices into the URL so a result is reproducible — that means YOU decide when to share. If the payload is sensitive (internal IDs, customer data, prod responses), copy the generated `.proto` instead of sharing the link. Only your syntax and optional-label preferences are stored in localStorage so your style persists across visits.

FAQ

Tool combos

Folks in your role tend to reach for these alongside this tool.

Made by Toolora · 100% client-side · Updated 2026-06-13