Schema on read
Schema on read
Why there is no schema to define, and what that costs you.
Fields are discovered at ingest and typed at query time. You never declare a schema, never run a migration, and never hit a mapping conflict because two services disagreed about whether id is a string or a number.
How it works
- 1
Ingest records the field
A new key in an incoming event is added to the dataset's field list with its observed type. No rewrite of existing blocks.
- 2
Storage keeps the raw value
Values are written into a columnar block exactly as they arrived, compressed. Nothing is coerced on the way in.
- 3
Query resolves the type
LSQL coerces at read time.
where status >= 500works whetherstatusarrived as503or"503".
When a field has two types
It is allowed. The field list shows both, and the query decides. Use toint() or tostring() when you need certainty — for example before a numeric comparison across a field that some senders quote.
1['api-gateway-prod']2| extend code = toint(status)3| where code >= 5004| summarize count() by serviceWhat it costs you
| You gain | You give up |
|---|---|
| No migrations, ever | No compile-time guarantee a field exists |
| New fields queryable within seconds | A typo in a sender becomes a new field, silently |
| No reindex when a shape changes | Field count can creep toward the 4,096 cap |
Watch the field count
user_8f21c4_latency instead of { user: "8f21c4", latency: … }. Check with GET /v1/datasets/:name/fields.