Logstreem
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. 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. 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. 3

    Query resolves the type

    LSQL coerces at read time. where status >= 500 works whether status arrived as 503 or "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.

Forcing a type
read top to bottom
1['api-gateway-prod']
2| extend code = toint(status)
3| where code >= 500
4| summarize count() by service

What it costs you

You gainYou give up
No migrations, everNo compile-time guarantee a field exists
New fields queryable within secondsA typo in a sender becomes a new field, silently
No reindex when a shape changesField count can creep toward the 4,096 cap

Watch the field count

The usual cause of field-count creep is putting a high-cardinality value in a *key* rather than a value — user_8f21c4_latency instead of { user: "8f21c4", latency: … }. Check with GET /v1/datasets/:name/fields.