Avro Schema Formatter

Paste a .avsc schema and get it indented, plus a check against the parts of the Avro spec that JSON.parse cannot see: union defaults, duplicate branches, legal names, and logicalType pairings.

Schema

.avsc

Formatted

read only

Load a sample or paste your own schema.

0Records
0Fields
0Unions
0Logical types
Load a schema

A schema that parses as JSON can still be an illegal Avro schema.

JSON.parse only checks brackets and quotes. It has no idea that a union cannot repeat a type, that a default has to match the first branch of a union, or that decimal needs a precision. Those rules live in the Avro specification, not in the JSON grammar, so a formatter that only pretty prints leaves every one of those mistakes for a Kafka consumer or a Spark job to hit at read time. This page runs both checks: JSON syntax first, then the Avro-specific rules, and shows you which one failed.

Why a broken schema still deploys and then breaks something else

Avro has no compiler step of its own. A producer writes bytes against a writer schema, a consumer reads them against a reader schema, and the two only have to agree at the moment of decoding. That means a malformed schema, a union with a default that cannot resolve, an enum missing a symbol another team expects, passes every check in your build pipeline and fails hours later inside a consumer service that has nothing to do with the code you shipped.

The five checks below catch what that failure would have looked like, before it reaches a topic.

What the type keyword is allowed to hold

Every Avro schema node needs a type. What comes after it branches into two very different shapes: eight fixed primitive names, or one of five complex forms that each carry their own required fields.

TypeShapeRequired alongside "type"
null boolean int long float double bytes stringPrimitiveNothing else. A bare string is the whole schema.
record / errorComplex, namedname, fields (an array, even if empty)
enumComplex, namedname, symbols (a non-empty array of legal names)
fixedComplex, namedname, size (positive integer bytes)
arrayComplex, unnameditems (another schema)
mapComplex, unnamedvalues (another schema, keys are always strings)

A union is written differently again, as a bare JSON array rather than an object with a type key. ["null", "string"] is a complete, valid schema by itself.

The union default rule nobody reads until it bites

Avro resolves a field default against the first branch of its union, not against whichever branch the default value happens to look like. Put the wrong branch first and a technically sensible default becomes an error.

Rejectedint first, default is null
{"name": "count", "type": ["int", "null"], "default": null}
Acceptednull first, default is null
{"name": "count", "type": ["null", "int"], "default": null}

Both schemas describe the same set of possible values. Only the second parses under a strict Avro reader, because the default's type is checked against index zero of the union array, and index zero has to be null for a null default to make sense.

This page checks structure, not your data. It confirms the schema itself follows the spec. It cannot tell you whether a record produced somewhere in your pipeline actually matches this schema, and it does not compare two schema versions for compatibility the way a Confluent Schema Registry or Karapace check would before allowing a new version onto a subject. Run this first, then run a compatibility check against your registry if one is in front of the topic.

Logical types change the meaning, not the bytes on the wire

A logicalType is metadata layered on top of a primitive or a fixed. The bytes written to disk stay exactly what the base type would write. Only a reader that knows the annotation interprets them differently, which is what makes a typo here so quiet.

Write "uuid-v4" instead of "uuid", a mistake that reads perfectly reasonably to a person, and every conforming Avro reader ignores it. The field still decodes. It just decodes as a plain string, with no error, no warning, and no hint that the annotation was ever there. That is the one class of mistake this page reports as a note rather than an error, since it is not illegal, only silently ignored.

A duplicate name means two different things depending on where it shows up

Inside one union, a repeated primitive type is a straight error. ["string", "string", "null"] cannot resolve which branch a string value belongs to, so Avro forbids it outright.

Across an entire schema document, a repeated record name is a namespace problem instead. Two records both named Address are fine if one carries com.toolexe.billing as its namespace and the other carries com.toolexe.shipping. Drop the namespace from either one and a schema registry that tracks subjects by full name will see the same identity twice, which is a common source of the "incompatible schema" rejection that shows up in Kafka producer logs with no line number attached.

What five mistakes look like together

Load the broken sample above and the report lists all of it at once: a record name with a space in it, a union repeating string, a default that does not match its union's first branch, a field with no type at all, and (once you fix the rest) a namespace-free record name colliding with nothing in this document but worth a second look anyway. Real schemas rarely fail this hard. They usually fail on exactly one of these, buried in a document three hundred lines long, which is the case this page is built for.

Reach for a different tool when the shape you have is not Avro

Avro schemas are a specific JSON dialect with union arrays, named types, and logicalType annotations. If what you actually have is a JSON document you want indented with no schema rules applied, the JSON beautifier does that without flagging anything as an Avro violation. If a JSON document will not parse at all, start with the JSON fixer to find the syntax break first. Going from JSON data toward Protocol Buffers instead of Avro, the JSON to Proto converter builds a .proto message from a sample payload. Going toward a JSON Schema document for validating API payloads, which is a different specification from Avro despite the name, the JSON to JSON Schema tool covers that instead.

Questions that come up once a real schema is loaded

What people ask after pasting a schema that has been rejected somewhere.

Does this validate data records against the schema?

No. It checks the schema document itself for structural and spec violations. Checking whether a specific JSON or binary record conforms to a schema needs a full Avro library, such as avro-js or the Java or Python Avro packages, running outside the browser.

Why does my schema format fine but still show errors?

Formatting only needs valid JSON. The errors come from a second pass that checks Avro-specific rules: legal names, union defaults, duplicate union branches, and logicalType pairings. A document can be syntactically perfect JSON and still break every one of those rules.

What is the difference between an error and a note in the report?

Errors are violations of the Avro specification that a strict reader would reject. Notes are things this page cannot fully verify on their own, mainly type references it cannot find defined anywhere in the pasted document, since that reference might live correctly in a companion schema file it never sees.

Is my schema sent anywhere?

No. Parsing and validation run as JavaScript in this browser tab. A schema describing an internal data model never leaves your machine, and nothing is stored once you close the tab.

Why does the default value error mention only the first union branch?

That is how the Avro spec defines default resolution for a union-typed field. The default is checked against index zero of the union array regardless of which branch actually matches the value's type, so the branch order in a nullable field matters.

Can this catch a schema evolution problem, like a field I removed breaking old consumers?

No. Backward and forward compatibility between two versions of a schema is a comparison this page does not run. That check belongs to whatever schema registry sits in front of your topic, or to the Avro SchemaCompatibility utilities if you are not using a registry.

What counts as a legal Avro name?

Letters, digits, and the underscore character, and the name cannot start with a digit. That rule applies to record, enum, and fixed names, to individual field names, and to enum symbols. Spaces, hyphens, and most punctuation are all illegal.

My schema references a type I know is defined, why does it show a note?

This page only sees the document you paste. If Type A references Type B and Type B is declared in a separate .avsc file that gets merged at build time or registered separately in your schema registry, this page has no way to see that file, so it flags the reference as unresolved within what it can read.