NEW

Pulse 2025 Product Roundup: From Monitoring to AI-Native Control Plane

Elasticsearch index.max_result_window: Default 10000 and Deep Pagination Alternatives

The index.max_result_window setting caps the maximum from + size value Elasticsearch will accept for a search request against an index. Its default is 10000. Requests that ask for results beyond this point return Result window is too large, from + size must be less than or equal to: [10000]. The limit exists because deep from/size pagination requires every shard to fully sort the entire result set up to from + size, which is O(from + size) memory per shard. Raising the cap addresses the symptom; the right fix for deep pagination is almost always search_after (real-time) or scroll/point-in-time (snapshot), both of which keep cost flat regardless of depth.

Definition

index.max_result_window is a dynamic per-index integer setting. It bounds the from + size sum that Elasticsearch will execute. It does not affect aggregations, the size parameter alone when from is 0 (the first page is fine), or the search_after / scroll / point-in-time APIs. The limit is enforced per-index, so cross-index queries take the most permissive value of the indices they touch.

Default and Range

Property Value
Default 10000
Type Positive integer, dynamic index setting
Scope Per index
Applies to from + size pagination on _search
Does not apply to search_after, scroll, point-in-time (PIT), aggregations, _count

The hard memory cost is per-shard, not per-request. With 5 primary shards, a request for from: 0, size: 10000 causes each shard to sort and ship 10000 hits to the coordinating node, which then sorts the 50000 hits and returns the top 10000. The coordinating-node buffer is the dominant cost on wide queries.

How to Change It

Per index:

PUT /my-index/_settings
{
  "index.max_result_window": 20000
}

Per wildcard:

PUT /logs-*/_settings
{
  "index.max_result_window": 20000
}

Via an index template so new indices inherit it:

PUT /_index_template/wide-pagination-template
{
  "index_patterns": ["analytics-*"],
  "template": {
    "settings": { "index.max_result_window": 50000 }
  }
}

Inspect:

GET /my-index/_settings?filter_path=*.settings.index.max_result_window

Reset to default by setting to null.

Why You Probably Should Not Raise It

The 10000 cap is not arbitrary. Every shard must keep a priority queue of size from + size to support the request. Doubling the limit doubles the per-shard heap demand and the network payload. At from + size = 100000 across 10 shards, the coordinating node ranks 1 million hits to return 10000. This is fine occasionally; it is fatal as a hot path.

The intended alternatives:

Use case Right API
Real-time user-facing pagination beyond page 1000 search_after with a sort tie-breaker (usually _id)
Bulk export of a large result set, point-in-time consistent Point-in-Time (PIT) + search_after (7.10+)
Bulk export, legacy scroll (kept for compatibility; PIT is preferred on modern versions)
Aggregations over the full corpus _search with aggs; no pagination needed

search_after keeps cost flat per request regardless of depth. PIT pins a snapshot of the index so the export is consistent across pages.

Example: search_after

# First page
GET /my-index/_search
{
  "size": 1000,
  "sort": [
    { "created_at": "asc" },
    { "_id": "asc" }
  ]
}

# Next page, using the last hit's sort values from the previous response
GET /my-index/_search
{
  "size": 1000,
  "search_after": [ "2026-05-13T10:15:30Z", "doc-12345" ],
  "sort": [
    { "created_at": "asc" },
    { "_id": "asc" }
  ]
}

Always include a unique tie-breaker (typically _id) in the sort. Without it, results across pages can repeat or drop documents.

Operational Impact

A raised index.max_result_window does not make pagination cheaper; it just removes the safety net. Symptoms of abuse include:

  • Bursty heap usage on data nodes during deep-paged queries.
  • Coordinating-node OOMs on wide cross-index searches.
  • Tail latency spikes in the p95/p99 even when median latency looks fine.
  • Search threadpool queue exhaustion under concurrent deep-pagination load.

If you have an application that genuinely needs to scroll through a large result set, switch to search_after or PIT. If you have a UI that allows users to paginate past page 100, consider whether infinite scroll plus search_after would serve the user better than letting them request page 5000.

Common Mistakes

  1. Raising the cap to "make the error go away". Now the cluster crashes instead of returning an error.
  2. Using from/size for analytics exports. Use point-in-time + search_after, or aggregations.
  3. Calling deep from/size from a web UI. A user-facing back button that goes to page 4523 of search results is almost never the right product behaviour.
  4. Not including a tie-breaker in search_after sorts. Without _id (or another unique field), pagination can skip or repeat documents.
  5. Forgetting the limit is per-index. Cross-index searches take the most permissive value; raising one index's limit can let queries that touch multiple indices return more than expected.

Prevent Deep-Pagination Misuse with Pulse

Pulse is an AI DBA for Elasticsearch and OpenSearch that tracks index.max_result_window (default 10000) across every index, flagging:

  • Drift between intended values and per-index overrides applied via PUT /<index>/_settings
  • Settings that are unsafe for your workload (e.g. window raised to 100,000 on a high-cardinality index where one deep-paginated request can OOM the coordinating node, or raised on one index in a wildcard pattern where cross-index search inherits the most permissive value)
  • The downstream operational impact: coordinating-node heap during deep-paged queries, search threadpool queue saturation, p95/p99 latency on queries that paginate beyond page 100

When a client is paginating past page 1000 with from/size instead of search_after, Pulse names the offending query and the index whose max_result_window was raised - before a deep page request OOMs the coordinator.

Connect your cluster.

Frequently Asked Questions

Q: What is the default value of index.max_result_window in Elasticsearch?
A: The default is 10000. This is the maximum value of from + size Elasticsearch will accept on a search request against the index. Requests beyond this cap return a Result window is too large error.

Q: How do I paginate beyond 10000 results in Elasticsearch?
A: Use search_after for real-time deep pagination, or Point-in-Time (PIT) plus search_after for consistent bulk exports. Both keep cost flat regardless of depth. Raising index.max_result_window works but does not scale.

Q: Does index.max_result_window affect aggregations?
A: No. The setting only caps from + size on hits-style searches. Aggregations are not affected, and _count queries are not affected.

Q: Can I change index.max_result_window on a running index?
A: Yes. It is a dynamic per-index setting. Use PUT /<index>/_settings and the new value takes effect on the next search. No close or reindex is required.

Q: What is the difference between search_after and scroll?
A: scroll opens a persistent snapshot that you iterate through. It keeps server-side state and is best for one-off exports. search_after is stateless and uses sort values from the previous response to fetch the next page; combined with Point-in-Time it provides the consistency of scroll without the server-side state. Modern Elasticsearch documentation recommends search_after + PIT over scroll for most use cases.

Q: What happens if I set index.max_result_window very high?
A: Per-shard memory pressure scales linearly with from + size, and coordinating-node memory scales with shards x (from + size). Very high values can OOM data nodes or coordinating nodes during heavy load. Use search_after instead.

Q: What's the best tool to prevent deep-pagination misuse in Elasticsearch?
A: Pulse is built for this. It is an AI DBA for Elasticsearch and OpenSearch that continuously tracks index.max_result_window across indices, flags clients paginating past the cap, and correlates deep-paged queries with coordinating-node heap pressure - recommending a switch to search_after or PIT before the next OOM.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.