Avro logicalType 'date' with default null value
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Yes, an Avro date logical type can have a default value of null, but the schema has to be written correctly. The key rule is that when a field uses a union, the default value must match the first branch of that union.
The Correct Nullable date Schema
Avro’s date logical type is stored physically as an int representing the number of days since the Unix epoch. If the field is optional, the usual pattern is a union of null and the logical date type.
This is the correct form when the default should be null:
This works because:
- the field is nullable
- the logical type is still represented correctly
- the default
nullmatches the first union member
That last point is the one that usually causes trouble.
Why Union Order Matters
In Avro, a field default must conform to the first type listed in a union. So this schema is wrong:
Even though null appears in the union, the default does not match the first branch. Many Avro implementations will reject that schema or behave unexpectedly when generating code or resolving schemas.
So the rule is simple:
- if the default is
null, put"null"first - if the default is a real date value, the first branch must match that representation instead
What the Date Value Looks Like
Because Avro logical types are annotations on primitive types, a date is still encoded as an integer count of days. That means if you ever use a non-null default for a date, the default must be an integer, not a formatted date string.
For example:
Here, 0 represents the epoch date in Avro’s physical storage model.
This is another source of confusion. Developers see logicalType: "date" and expect the default to be something like "2025-01-09", but Avro defaults must still follow the underlying primitive representation.
A Full Record Example
Here is a small record schema that uses an optional date correctly:
With this schema, a record can omit hireDate, and Avro readers will use null as the default.
Why This Matters for Schema Evolution
Nullable fields with defaults are common in schema evolution. Suppose you add hireDate to an existing record type after older data has already been written. If the new field has:
- a nullable union
- a valid default
then older records can often be read safely because the reader schema knows what value to supply when the field is missing.
That is one reason the default: null pattern is so common. It is not only about optional data in newly written records. It also helps compatibility when schemas evolve.
Testing the Schema in Practice
If you generate code or validate schemas in a build pipeline, test the union form early. Different Avro libraries often agree on the spec rule, but the error messages can vary a lot.
A good practical check is:
- validate the schema
- serialize a record with the field omitted
- deserialize it with the same schema
- confirm the field resolves to
null
That catches both schema mistakes and library-specific assumptions before the schema reaches production.
Common Pitfalls
The most common pitfall is putting the logical date branch first and null second while still using default: null. That violates Avro’s union-default rule.
Another mistake is supplying a string such as "2025-01-09" as the default for a date logical type. Avro defaults follow the underlying primitive type, which is int for date.
A third issue is assuming logical types change the schema-default rules. They do not. Logical types add meaning, but the primitive representation still governs encoding and defaults.
Finally, some teams validate the schema only in one language binding. If the schema will be shared across systems, validate it in the toolchain that will actually consume it.
Summary
- An Avro
datelogical type can have a defaultnullvalue. - To do that correctly, use a union with
"null"as the first branch. - The default must match the first type in the union.
- Avro
datevalues are stored asintday counts, not formatted date strings. - This pattern is especially useful when adding optional date fields during schema evolution.

