What is an Elasticsearch runtime field, and when do you use one instead of reindexing?
answer
- The value is produced, not stored
- Definable per query as well as per index
- No script means it reads the stored document
- You pay once per document examined, every time
- Promote it once the queries prove it earns storage
basics
~20 sA runtime field is defined in the mapping or in a search request and evaluated per document at query time, usually from _source, with nothing written to the index. It gives schema-on-read: add, change or drop it instantly, and pay the cost on every query instead.
solid answer
~50 sA runtime field is a field with no index-time footprint. You declare it in the index mapping's `runtime` section or per-search in `runtime_mappings`, giving a type and usually a Painless script that calls `emit()`; without a script it simply reads the value of the same name from `_source`. It can be queried, filtered, sorted, aggregated and returned through the search `fields` parameter, but there are no postings and no doc values behind it — Elasticsearch runs the script for every document the query has to consider. That makes it the right tool when you need a field **now** on data already indexed: fixing a wrongly typed or missing field, deriving a value from existing ones, or exploring log data whose shape you do not yet know. Reindexing is the right answer once the field is queried routinely, because an indexed field is orders of magnitude cheaper to search. The usual pattern is runtime first, promote later.
code
json · 9 linesPUT /orders/_mapping
{
"runtime": {
"total_with_tax": {
"type": "double",
"script": { "source": "emit(doc['total'].value * 1.2)" }
}
}
}go deeper
Know that a runtime field is computed at query time rather than stored, that it can be added without reindexing, and that you request its value through the search fields parameter.
Explain both places it can be defined, the emit-based script, the no-script _source fallback, and why the absence of postings and doc values makes queries on it scale with documents examined.
Show the judgment: runtime for exploration, corrections and rare fields; indexed for hot paths. Explain how to keep one affordable by filtering on indexed fields first and reading doc values rather than _source.
Own the index-a-core, explore-the-tail strategy — what gets indexed by default, how promotion decisions are evidenced by real query traffic, and how you stop convenient runtime definitions becoming permanent hot-path cost.
## Schema on read Elasticsearch's normal model is schema-on-write: analysis and doc-value construction happen once at index time, and queries then read prepared data structures. A runtime field inverts that for one field. Nothing is prepared; the value is produced when a query asks for it. You define one in either of two places: - **In the index mapping**, under a top-level `runtime` object. This makes the field part of the index's schema — it appears in field-caps output and Kibana's field list — and it can be added, changed or removed with a mapping update at any time, taking effect on existing documents immediately. - **In a single search request**, under `runtime_mappings`. This is scoped to that one query, which makes it ideal for exploration and for one-off reports, and a search-request runtime field can shadow an indexed field of the same name for that query. A definition is a type plus, optionally, a script: ```json "runtime": { "duration_ms": { "type": "long", "script": { "source": "emit(doc['end'].value.toEpochMilli() - doc['start'].value.toEpochMilli())" } } } ``` The script calls `emit()` — once for a single value, repeatedly for a multi-valued field, or not at all for a document where the value does not exist. Supported types include `keyword`, `long`, `double`, `boolean`, `date`, `ip`, `geo_point` and `composite` (which emits several sub-fields from one script). **If you omit the script entirely**, the runtime field reads `_source` for a field of the same name — which is exactly how you make data that landed under `dynamic: false` queryable without touching a single document. ## Where the cost lands An indexed `keyword` term query is a dictionary lookup that jumps straight to a postings list. A runtime-field query has no such structure: Elasticsearch iterates candidate documents, runs the script on each, and tests the emitted value. If the script reads `_source`, each evaluation also means fetching and decompressing the stored source of that document, which dominates. If it reads `doc['other_field']` — doc values on an already-indexed field — it is markedly cheaper, though still per-document work. The practical consequence is that a runtime field's cost is proportional to how many documents the query makes it visit. A runtime clause combined with a selective indexed filter (a time range, a tenant term) evaluates over a small candidate set and feels fine; the same clause alone over a billion-document index does not. Structure queries so the indexed predicates run first, and be careful about sorting on a runtime field, which forces evaluation across the whole matching set rather than a filtered slice. ## When each option is right **Use a runtime field when:** - you need to query something on data that is already indexed and reindexing is too slow or too expensive right now; - the field is derived — a unit conversion, a concatenation, a bucket label, a value parsed out of a message; - the field is rare or exploratory and you would rather not pay index size and ingest cost for it; - you are patching a mistake: a field mapped as the wrong type in old indices can be presented consistently through a runtime field of the correct type; - the definition itself is still changing, since a runtime field can be edited freely while an indexed field's type cannot. **Reindex into an indexed field when:** - the field is used in hot-path queries, or by many dashboards; - it is filtered by many users concurrently, so per-query script cost multiplies; - you need full-text analysis on it, which runtime fields do not provide; - the workload sorts or aggregates on it over large result sets routinely. Elastic's own recommended pattern is to index a modest core of well-understood fields, keep the long tail as runtime fields, and **promote** a runtime field to an indexed one when it proves it is worth the storage — a decision you can make with evidence rather than up front. ## Things that surprise people Runtime fields are not returned in `_source` (there is nothing stored to return) — you must ask for them by name in the search request's `fields` parameter. They do not participate in full-text analysis. A script error at query time surfaces as a search failure rather than an indexing failure, so a bad definition breaks reads, not writes. And a runtime field defined in the mapping does count as part of the index's schema, so it is visible to every consumer of that index rather than only to the query that invented it.
- How do you retrieve a runtime field's value in search results?Through the search request's `fields` parameter, naming the runtime field. It cannot come back in `_source`, because nothing is stored for it — the value only exists once the script has run. `fields` triggers that evaluation and returns the emitted values alongside the hit.
- A runtime field query is unusably slow. What do you try before reindexing?First, make sure selective indexed predicates — a time range, a tenant filter — constrain the candidate set so the script runs on far fewer documents. Second, rewrite the script to read doc values of indexed fields rather than `_source`, avoiding source decompression. Avoid sorting on the runtime field. If it is still hot, that is the signal to promote it to an indexed field.
- How do runtime fields help with data that was indexed under dynamic: false?Those values are still in `_source`, just not indexed. Defining a runtime field with the same name and no script makes Elasticsearch read that value from `_source` at query time, so the previously invisible data becomes queryable immediately — across documents indexed long before the definition existed, with no reindex.
saying these in an interview costs you the question
- Thinks runtime fields are indexed lazily and then cached
- Expects runtime field values to appear in _source
- Claims they are free because they use no disk
- Uses one as a hot-path filter over a whole index
- Believes changing a runtime field requires a reindex