skip to content

How does refresh=wait_for on an Elasticsearch index request differ from refresh=true?

level: middleimportance: should knowfreq 52%

answer

  1. both give read-your-writes, at different prices
  2. one forces work, one just waits
  3. think about how many segments get created
  4. a per-shard listener limit exists
  5. under load one silently becomes the other

basics

~20 s

refresh=wait_for holds the response until the next scheduled refresh makes the change visible, forcing no extra work. refresh=true forces an immediate refresh of the affected shards, creating an extra segment per request and much more merge pressure.

solid answer

~50 s

Both give you read-your-writes on that request; they differ in who pays. `refresh=wait_for` does not trigger anything — it registers a listener and blocks the response until the shard's next refresh happens anyway, so the latency you see is up to `index.refresh_interval` but the cluster does no extra work. `refresh=true` forces the affected shards to refresh right now and only then responds, which is faster for the caller but cuts a new segment per request and drives merge load on a busy index. In practice `wait_for` is the right default for the rare request that genuinely needs immediate visibility, and `true` is reserved for tests or one-off admin operations. One caveat: each shard has a bounded number of pending refresh listeners (`index.max_refresh_listeners`); if a shard exceeds it, further `wait_for` requests fall back to forcing a refresh, so hammering `wait_for` under load degrades into `true`.

go deeper

for a junior

Remember there is a refresh parameter on write requests with three values, and that wait_for waits for the next scheduled refresh instead of forcing one.

for a middle

Explain the segment-count consequence: many refresh=true writes mean many tiny segments and merge work, while wait_for lets callers share one refresh.

for a senior

Show the operational failure mode — the refresh-listener bound turning wait_for into true under load — and argue for fixing the read path or batching instead.

for a principal

Decide where read-your-writes belongs as a product contract: which flows truly need it, whether it should be served by a real-time get instead, and what visibility latency you publish per index class.

## The problem both options solve Elasticsearch search is near-real-time: a document becomes searchable only once a refresh has turned the shard's in-memory buffer into a Lucene segment, by default about once per second. Some workflows cannot tolerate that: a user saves a record and is immediately redirected to a list view that queries the index, or an integration test asserts on a search straight after a write. The `refresh` parameter on the index, update, delete and bulk APIs exists for exactly these cases. ## The three values - **`refresh=false`** (default) — do nothing extra; visibility happens whenever the next scheduled refresh runs. - **`refresh=wait_for`** — do not trigger a refresh; instead hold this response open until a refresh has occurred that makes this change visible, then respond. - **`refresh=true`** — force an immediate refresh of the shards touched by this request, then respond. ## Why wait_for is usually the better choice The key insight is that a refresh is a *per-shard* operation whose cost is amortised over everything in the buffer. If a hundred writes land in the same second and each one sets `refresh=true`, you have forced up to a hundred refreshes and produced up to a hundred small segments, each of which now has to be merged in the background — CPU, I/O, file handles, and a longer per-query segment list. If those same hundred writes use `wait_for`, they all attach to the same upcoming refresh: one segment, one refresh, and every caller returns at roughly the same moment. The cost of `wait_for` is latency in the caller. The request will block for up to `index.refresh_interval`, so a client that indexes with `wait_for` in a tight loop serialises itself at one document per refresh cycle. The fix there is to batch: send a bulk request with `refresh=wait_for` once rather than N single writes with it. ## The listener limit A shard tracks pending `wait_for` requests as refresh listeners, and the number it will hold is bounded by `index.max_refresh_listeners`. When that bound is exceeded, additional requests do not fail — they fall back to forcing a refresh, i.e. they behave like `refresh=true`. This matters operationally: a system that puts `wait_for` on a high-throughput write path does not stay cheap under load; it degrades into exactly the segment storm you were trying to avoid. ## The standalone refresh API `POST /index/_refresh` refreshes an entire index on demand, independently of any write. It is the natural tool in a test harness (write a batch, refresh once, assert) and in bulk-load pipelines where `index.refresh_interval` was set to `-1` for the duration of the load and you want one refresh at the end. ## What this does not give you Neither value has anything to do with durability. Durability is the translog's job, governed by `index.translog.durability`; a refresh writes segments to the filesystem cache and never fsyncs. A request that returned with `refresh=true` is no more crash-safe than one that returned with `refresh=false`. Equally, neither one gives cluster-wide guarantees beyond the shards involved. `wait_for` guarantees that *this change* is visible when the response arrives; it says nothing about other concurrent writes to other shards. ## Choosing in practice Ask who needs the visibility. If it is a single user-facing flow, put `wait_for` on that one write and leave everything else alone. If it is a test, `wait_for` or an explicit `_refresh` between phases is clean and deterministic — much better than a sleep. If you find yourself wanting it on the majority of writes, the real answer is usually to fix the read path instead: fetch the just-written document by id (the get API is real-time) rather than searching for it.

  • What is the latency ceiling a caller sees with refresh=wait_for?
    Roughly `index.refresh_interval`, since the request waits for the next scheduled refresh — about a second on default settings. If the index has been tuned to 30s, `wait_for` blocks for up to 30s, which surprises teams that tuned the interval for ingestion and then reused the same index in a user-facing flow.
  • Your service sets refresh=wait_for on every write and it is fast in staging but causes segment explosions in production. Why?
    Each shard only holds a bounded number of refresh listeners (`index.max_refresh_listeners`). Once production throughput pushes past that bound, extra `wait_for` requests fall back to forcing a refresh, so the workload behaves like `refresh=true` and cuts a segment per request. Staging never reached the bound.
  • Is there a way to get read-your-writes without touching refresh at all?
    Yes — read the document by id. The get API is real-time and can serve the document out of the translog before any refresh. If the UI flow can fetch the specific record instead of running a search, it needs no refresh parameter and imposes no cost on the index.

saying these in an interview costs you the question

  • Says wait_for triggers a refresh immediately
  • Claims either option makes the write durable
  • Puts refresh=true on the whole production write path
  • Assumes wait_for cannot ever force a refresh
  • Thinks the parameter guarantees visibility of other concurrent writes

context