JSON to Avro Schema
Generate an Avro schema from a JSON sample. Objects become record types, arrays become array types, and optional fields become a ["null", T] union with a null default — the shape Kafka's schema registry needs for a backward-compatible field.
How to generate an Avro 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 Namespace — Avro full names are
namespace.Name, and a registry will usually expect one. - Review the nullable unions: field order inside a union matters for defaults, and
nullmust come first for anulldefault to be valid. - Copy the code, or download it as a file.
Type mapping
- Integers →
long. Narrow tointif values fit in 32 bits. - Fractional numbers →
double. - Booleans →
boolean; strings →string. - Arrays →
{"type": "array", "items": …}. - Objects → a nested
record. - Optional / nullable →
["null", T]with"default": null. - Mixed or null-only →
string, which you should replace with a real union once you know the possibilities.
Field names are converted to snake_case, since Avro names must match
[A-Za-z_][A-Za-z0-9_]*. Where the JSON key differs, an aliases entry preserves
it — that is also what lets a reader resolve data written under the old name.
Schema evolution rules to keep in mind
- Adding a field is backward compatible only if it has a default. That is why optional fields here get
"default": null. - Removing a field is forward compatible only if the field had a default in the old schema.
- Renaming requires an
aliasesentry, or readers cannot find the old data. - Changing a type is only safe within Avro's promotion rules —
inttolongtofloattodouble, in that direction.
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
Why is my nullable field a union instead of just the type?
Avro has no separate nullability flag. A field that can be null is literally a union of null and the type, and null is listed first so "default": null is valid — Avro requires the default to match the union's first branch.
Can it emit logical types for timestamps?
Not automatically. An ISO 8601 string is a string as far as the sample shows. To get {"type": "long", "logicalType": "timestamp-millis"} you must also change the value to epoch millis on the producer side.
Is the output valid for Confluent Schema Registry?
The schema itself is valid Avro. The registry additionally enforces your subject's compatibility policy, so check a new version against the previous one before registering it.