Data Types
Overview
Template IDL version: 2 is semantic-first.
Authors declare the meaning of a field once, and the compiler derives:
- Java binding type
- protobuf wire type
- compatibility rules for schema evolution
Normal v2 authoring does not require protoType.
Legacy v1 templates that still declare type + protoType remain supported for backward compatibility, but v2 is the preferred model.
Canonical Semantic Types
Supported built-ins in v2:
stringboolint32int64float32float64decimaluuidtimestampdatetimedatedurationbytescurrencyuripath
Structural type:
map
map is a parameterised collection type, not an atomic scalar. It must declare keyType and valueType. keyType must be one of string, bool, int32, or int64. Message references, nested maps, and other structured types are not valid map keys. Map keys are limited to these scalar types because keys must be hashable and to ensure compatibility with protobuf wire-format encoding and deterministic map semantics.
Enums are not a first-class canonical v2 type in the current schema. Model them with named messages and string-backed fields for now, or keep legacy enum handling in v1 compatibility paths until explicit enum support is added.
PascalCase type tokens are treated as references to top-level named messages.
Example:
messages:
Money:
fields:
- number: 1
name: amount
type: decimal
- number: 2
name: currency
type: currencyDefault Compiler Mappings
Default wire and Java bindings:
decimal-> protobufstring, JavaBigDecimaluuid-> protobufstring, JavaUUIDtimestamp-> protobufstring, JavaInstantdatetime-> protobufstring, JavaLocalDateTimedate-> protobufstring, JavaLocalDateduration-> protobufstring, JavaDurationcurrency-> protobufstring, JavaCurrencyuri-> protobufstring, JavaURIpath-> protobufstring, JavaPathbytes-> protobufbytes, Javabyte[]
Important semantic distinctions:
timestamp: absolute point in timedatetime: local/civil date-time without timezone semanticsdate: calendar date only
currency, uri, and path stay first-class semantic types even though protobuf uses string by default.
Collections and Messages
Use repeated: true for lists:
- number: 3
name: labels
type: string
repeated: trueUse type: map for maps:
- number: 4
name: metadata
type: map
keyType: string
valueType: stringInvalid example:
Money is invalid as a keyType because map keys must be scalar values. Money is a composite message type, so name: invalidIndex cannot use it as a key.
- number: 5
name: invalidIndex
type: map
keyType: Money
valueType: stringUse PascalCase message names for references:
- number: 2
name: money
type: MoneyReserved Fields and Compatibility
Named messages can declare reserved numbers and names:
messages:
ChargeResult:
fields:
- number: 1
name: paymentId
type: uuid
reserved:
numbers: [4, 5]
names: ["legacyCode"]The compiler emits a normalized IDL snapshot and can compare it against a baseline using -Dtpf.idl.compat.baseline=<path>.
Breaking changes fail compatibility checks when they:
- renumber fields
- change canonical field types
- change structural shape, such as adding
repeated: trueto a singular field, changing a map key or value type, switching a field to a different message reference, or changing between optional and required semantics - remove fields without reserving the old number and name
- reuse reserved numbers or names
Optionality and Nullability
Fields are singular by default:
optional: falseunless explicitly setrepeated: falseunless explicitly set
Use optional: true when presence is part of the contract:
- number: 6
name: approvalCode
type: string
optional: truerepeated: true remains the list syntax for list fields and cannot be combined with optional: true.
Changing a field's optional flag across schema versions is a breaking change.
Advanced Overrides
Overrides are optional and intended for exceptional cases only.
- number: 2
name: amount
type: decimal
overrides:
proto:
encoding: stringOverrides are validated against the canonical type model.
- Unsafe or lossy encodings, such as mapping
decimaltodouble, are rejected. - Encodings must remain compatible with the canonical semantic type.
- Message and map structures cannot be overridden into incompatible wire forms.
Legacy v1 Note
v1 templates still allow:
- name: amount
type: BigDecimal
protoType: stringThat shape is legacy compatibility only. New templates should use semantic v2 fields and top-level messages.