The Scroll API in Elasticsearch

The Scroll API in Elasticsearch

Learn how Elasticsearch lets you read a very large set of results in steady batches from a frozen view of the data, how that view is kept alive inside the cluster, and when it is the right tool or the wrong one.

Imagine a public library that holds ten million index cards. A researcher needs a copy of every card that mentions a certain topic, and there may be two million of them. The librarian cannot hand over two million cards in one armful. Instead, the librarian takes a photograph of the whole card catalogue as it looks right now, gives the researcher a numbered ticket, and says: “Come back with this ticket, and I will hand you the next tray of one thousand cards each time.”

Even while the researcher walks back and forth, new cards may be filed in the real catalogue and old ones may be thrown away. It does not matter, because every tray comes from the photograph taken at the start. When the researcher has all the cards, the ticket is returned and the photograph is put away. That ticket and that photograph are the heart of the Scroll API in Elasticsearch.

1The Problem: Too Many Results for One Answer

Search is easy when you want ten hits. It gets hard when you want ten million.

Elasticsearch is a search and analytics engine. Most searches ask for a small answer, such as the top ten products or the latest fifty log lines. But real projects also need to read everything that matches. A team may need to export all customer records to a spreadsheet, copy an entire index into a new index, feed millions of documents into a machine learning job, or run a nightly report over a whole month of events.

Asking for everything in one response is impossible in practice. The answer would be enormous, it would exhaust memory on the servers and on the client, and it would take so long that the connection might time out. So the work must be split into many small steps. The real question is how to split it so that each step continues exactly where the last one stopped, without missing documents and without repeating any.

Simple Analogy

Think of moving house. You cannot carry the whole house in one trip. You make many trips with the car, and you need a checklist so that you never forget an item and never carry the same sofa twice. The Scroll API is that checklist for search results.

A second difficulty: the data keeps changing

Elasticsearch is usually a live system. While your export runs for ten minutes, other programs may add new documents, update old ones and delete some. If each trip looked at the current state of the index, you could see a document twice, because it moved position, or miss one entirely, because it shifted past your bookmark. A trustworthy export needs a stable picture of the data for the whole journey.

Many trips
results are delivered in small batches
One picture
every batch comes from the same frozen view
One ticket
a scroll ID marks your place

The Scroll API solves both difficulties together. It gives you batches, and it gives you a consistent view. As you will see, it pays for this with some resources held inside the cluster, and it has a newer relative that is now preferred for many jobs. Understanding both the power and the price is the goal of this tutorial.

2What Is the Scroll API?

A plain definition, then the words you will keep meeting.

The Scroll API is an Elasticsearch feature that lets you run one search and then fetch its results in many consecutive batches, all taken from a consistent snapshot of the data as it was when the search began. It works like a cursor in a traditional database: you open it, read from it repeatedly, and close it when you are done.

The process starts with an ordinary search request that carries one extra piece of information, a time value telling Elasticsearch how long to keep the search alive between batches. The response contains the first batch of documents and a special identifier called the scroll ID. You then send that ID back in follow-up requests, and each one returns the next batch, until a response comes back with no documents left.

Words you need to know

Term 1

Scroll

The overall operation of reading a large result set in batches from a frozen view, like turning through the pages of a long scroll.

Term 2

Scroll ID

A token returned by Elasticsearch that identifies your open scroll. You send it back to get the next batch.

Term 3

Batch

One group of hits returned by a single scroll request. Its size is set by the size parameter of the first search.

Term 4

Keep-alive

The time value that says how long each shard should hold your scroll open after serving a batch. It is refreshed on every request.

Term 5

Search context

The internal object each shard keeps to remember your frozen view and your position. It is what makes a scroll stateful.

Term 6

Snapshot view

The state of the index at the moment the scroll began. Later changes to documents are not visible inside the scroll.

Term 7

Sliced scroll

A way to divide one scroll into several independent parts that can be read in parallel by different workers.

Term 8

Clear scroll

An explicit request that closes a scroll early and frees the resources it holds.

i
Current guidance

Elastic’s documentation says the scroll API is no longer recommended for deep pagination. For paging through more than ten thousand hits while keeping a stable view, the newer approach of a point in time combined with search after is preferred. Scroll is still used widely, including inside Elasticsearch’s own reindex feature, so you must understand it either way.

“A scroll is a bookmark inside a photograph of your index.”

3Why Normal Search Cannot Go Deep

To appreciate the scroll, first see why ordinary paging breaks down.

The simplest way to page through results is to use the from and size parameters. The first page has from zero and size ten. The second page has from ten and size ten. And so on. This is fine for a user browsing a few pages of results. It becomes a problem for deep pages, and the reason lies in how Elasticsearch distributes the work.

The hidden cost of deep pages

An index is split into shards, and each shard searches its own data. Suppose you want the page starting at position one hundred thousand with ten results. Each shard cannot just return its own ten. It must find its top one hundred thousand and ten hits and send them to the coordinating node, which merges all of them from every shard, sorts them and throws away all but the last ten. The deeper you go, the more each shard and the coordinator must work, and the memory grows with the depth.

flowchart TD
    A["Client asks for page at from 100000, size 10"] --> B["Coordinating node"]
    B --> C1["Shard 1 finds its top 100010"]
    B --> C2["Shard 2 finds its top 100010"]
    B --> C3["Shard 3 finds its top 100010"]
    C1 --> D["Coordinating node merges 300030 hits"]
    C2 --> D
    C3 --> D
    D --> E["Sorts, drops 100000 hits, keeps 10"]
    E --> F["Client receives only 10 hits"]
        
FIG 1 — Deep paging makes every shard and the coordinator do far more work than the ten hits returned

The safety limit

To protect the cluster, Elasticsearch sets a limit called index.max_result_window, ten thousand by default. A request whose from plus size goes beyond that limit is rejected. This is a wise guard. It means ordinary paging can reach only the first ten thousand hits of any search.

Simple Analogy

Imagine asking three librarians, each in a different wing, to find the entries ranked 100,001 to 100,010 in a giant contest. Each librarian must first rank and count their own hundred thousand entries just to be able to tell you where their contribution falls. The work is enormous, yet you asked for ten entries.

The data-changes problem again

Paging with from and size also suffers from the shifting-data problem. Each page request is a fresh search of the current index. If a document is added between page one and page two, every later position shifts by one, and you may see one result twice or miss one. The scroll fixes both issues, since it holds one view and moves a cursor through it.

!
Common misconception

Raising the maximum result window to a huge number is not a real fix for deep paging. It only removes the safety rail while the cost keeps growing with depth. Use a method that is built for reading many results instead.

4The Big Idea: A Frozen View and a Bookmark

Two simple ideas combine to make scrolling work.

The first idea is the frozen view. When you start a scroll, each shard involved in the search takes note of the exact state of its data at that moment and promises to keep serving from that state until the scroll ends. New documents that arrive later, updates to existing documents and deletions are all ignored by that scroll. This is often called a snapshot, though it is unrelated to the backup feature that has the same name.

The second idea is the bookmark. Each shard remembers how far it has already delivered. When you ask for the next batch, the shard continues from its bookmark instead of starting the search again from the top. Because it continues, the work of each batch stays about the same however far you have travelled. Deep positions cost no more than early positions.

Simple Analogy

Reading a photocopied book with a physical bookmark is quick, no matter which page you are on. Reading a library book by asking a clerk “please count to page 4,000 and read me the next ten lines” every time would be painfully slow. The bookmark saves the counting.

Stateful means the cluster remembers you

A normal search is stateless. Once the response is sent, the cluster forgets the request. A scroll is stateful. The cluster must remember your frozen view and your position between requests. That memory lives inside the search contexts on the shards, and it is the source of both the strengths and the costs of scrolling. Anything kept alive on your behalf uses memory, file handles and disk space, so it must eventually be released.

PropertyOrdinary search with from and sizeScroll
Remembers state between requestsNoYes, in a search context on each shard
Sees changes made between pagesYes, each page is a fresh searchNo, it uses the frozen view
Cost of deep positionsGrows with depthRoughly the same for each batch
Depth limitTen thousand by defaultNot limited by the result window
Cleanup neededNoneYes, contexts should be cleared or allowed to expire
Suited toUser-facing pages of resultsBatch reading and data export
i
Key insight

Every property of the scroll, good or bad, follows from one fact: Elasticsearch must hold a frozen view for you. Keep that fact in mind and the rest of the tutorial will feel natural.

5The Scroll Flow, Step by Step

A scroll always follows the same three phases: open, read repeatedly, close.

1

Open with an initial search

You send an ordinary search request to an index, add the keep-alive time and a batch size, and optionally a sort. Elasticsearch creates search contexts on the shards and runs the query.

2

Receive the first batch and a scroll ID

The response contains the first group of hits, plus the scroll ID that represents your open scroll.

3

Process the batch

Your program does whatever it needs with those hits: write them to a file, transform them, send them onward.

4

Ask for the next batch

You call the scroll endpoint with the most recent scroll ID and a fresh keep-alive time. The shards continue from their bookmarks and return the next hits.

5

Repeat until a batch comes back empty

An empty list of hits means every matching document has been delivered. The loop stops.

6

Clear the scroll

You send a clear request with the scroll ID, so the shards can release the frozen view immediately instead of waiting for the keep-alive to run out.

sequenceDiagram
    participant C as Client
    participant N as Coordinating Node
    participant S as Shards
    C->>N: Initial search with scroll time and batch size
    N->>S: Create search contexts and run query
    S-->>N: First hits and context references
    N-->>C: First batch and scroll ID
    loop Until a batch is empty
        C->>N: Scroll request with scroll ID and new keep-alive
        N->>S: Continue from each bookmark
        S-->>N: Next hits
        N-->>C: Next batch and scroll ID
    end
    C->>N: Clear scroll
    N->>S: Release search contexts
        
FIG 2 — The life of a scroll from opening to clearing

The scroll ID may change

Each response includes a scroll ID. In many cases it stays the same, but the documentation says it can change between requests, so always use the most recent one you received. Treat it as an opaque token. Never try to read or build it yourself.

Where the ID travels

The scroll ID can be long, especially for indices with many shards, since it encodes references to each shard’s context. For that reason, send it in the body of the request instead of the web address, to avoid hitting limits on address length.

!
Common mistake

Forgetting to send the new keep-alive value in each scroll request. If you omit it, the contexts may expire after the original short time, and your next request will fail with a missing search context error.

6The Keep-Alive Time

The most misunderstood part of scrolling is how long it should stay alive.

The time you give, such as one minute, is not the total time of the whole scroll. It is the time the shards will hold your context after each request. Every request that reaches the shards resets that timer. So a scroll of two hours may work perfectly with a keep-alive of only one minute, as long as you always come back for the next batch within that minute.

Simple Analogy

A library reading room lets you keep your table reserved for five minutes whenever you step out. Each time you return and touch your papers, the clock starts again. You may keep the table all day, as long as you never leave it for more than five minutes at a time.

How to choose a value

The keep-alive should be long enough to process one batch and come back for the next, with a healthy safety margin. It should not be long enough to cover the entire job. A shorter value means that if your program crashes, the cluster releases the resources sooner. A longer value gives more room for slow processing but holds resources longer after a failure.

SituationReasonable keep-aliveWhy
Fast in-memory processing of each batchOne minutePlenty of time and quick release after a failure
Batch is written to a slow remote systemSeveral minutesCover the slowest expected batch
Workers pause between batches for rate limitingLonger than the pause plus processingAvoid expiry during the wait
Unknown or variable processing timeMeasure first, then add a marginPrevents both premature expiry and waste

The cluster ceiling

Elasticsearch protects itself with a maximum keep-alive, controlled by the setting search.max_keep_alive, which is twenty-four hours by default. Asking for a longer time is rejected. There is also a default keep-alive for cases where none is given, controlled by search.default_keep_alive. Both are cluster settings that an administrator can adjust, though raising the maximum should be done with care.

i
Practical tip

Time your first few batches during a test and set the keep-alive to several times the slowest one. Then watch for missing context errors in production, which are a clear sign that some batches take longer than you assumed.

!
Common mistake

Setting the keep-alive to hours “to be safe”. If the client crashes, the frozen view stays on the cluster for all those hours, holding memory, file handles and disk space. Prefer short values that are refreshed on every request.

7Batch Size and Sorting

Two small choices strongly affect how fast a scroll runs.

The batch size

The size parameter of the first search decides how many hits each batch contains. A larger size means fewer round trips, but each response is bigger and needs more memory on the servers and on your client. A very small size makes the job chatty and slow. A common starting range is between several hundred and a few thousand documents per batch, adjusted to document size and network speed.

There is a limit here as well. The size of a scroll batch must not exceed the index result window setting, ten thousand by default, because a scroll batch costs as much memory as a result window of the same size. If you ask for more, Elasticsearch replies with an error that mentions this setting.

Factor 1

Document size

Large documents make each batch heavy. Use a smaller size for big documents, and a larger one for small ones.

Factor 2

Network speed

A slow network favours fewer, larger batches, while a fast local network handles many small ones easily.

Factor 3

Client memory

The whole batch must fit in the client’s memory along with whatever processing you do on it.

Factor 4

Source filtering

Ask only for the fields you need. Smaller hits mean faster batches at any size.

The sort order

If you do not care about the order of the documents, ask for them sorted by the special value _doc. This means “in the natural index order”. Elastic’s documentation notes that scroll requests are faster when sorted this way, because Elasticsearch does not have to compare and order documents by score or by a field, and each shard can simply walk through its data.

Sort choiceSpeedWhen to use
By the _doc valueFastestExports and copies where order does not matter
By relevance scoreSlowerWhen you truly need best matches first, rare for large scrolls
By a field such as a timestampSlower, needs sorting workWhen downstream processing needs chronological order
Simple Analogy

If you only need to photocopy every card in a drawer, you take them in the order they sit. If someone insists that the copies come out alphabetically, you must sort as you go, and the job takes longer.

i
Practical tip

If you need ordered output but the order is not required during transfer, scroll unsorted using the natural order and sort afterwards in your own system, where sorting a large file is often cheaper than forcing the cluster to sort during every batch.

8Ending a Scroll: Clearing the Search Context

Finishing politely is part of the contract.

A scroll ends in one of three ways. The best way is that your program finishes reading and sends a clear scroll request naming the scroll ID. Elasticsearch then releases the search contexts on every shard at once. The second way is that the keep-alive expires because no request touched the scroll in time, and the contexts are removed automatically. The third way is a failure, such as a node restart, which destroys the contexts along with the node’s memory.

Why you should always clear

Automatic expiry is a safety net, not a plan. If you rely on it, then for the entire keep-alive after your last request the cluster keeps holding a frozen view that nobody will read. Multiplied by many jobs, this quickly adds up. Clearing a finished scroll is a small extra call that returns resources at once.

flowchart TD
    A["Scroll is open"] --> B{"How does it end?"}
    B -->|Client sends clear request| C["All shard contexts released immediately"]
    B -->|Keep-alive runs out| D["Contexts expire and are removed automatically"]
    B -->|Node restarts or shard is lost| E["Context disappears, next request fails"]
    C --> F["Resources returned right away"]
    D --> G["Resources held until the timeout"]
    E --> H["Client must start a new scroll"]
        
FIG 3 — Three ways a scroll can end, and when resources come back
Option 1

Clear one scroll

Send the specific scroll ID to the clear endpoint. This is the normal way to finish.

Option 2

Clear several scrolls

Send a list of scroll IDs together, useful for sliced scrolls where each slice has its own ID.

Option 3

Clear all scrolls

A special value clears every open scroll for the user. It is handy in emergencies, but it can disrupt other jobs, so use it with great care.

Simple Analogy

When you finish using the library’s photograph of the catalogue, you hand back your ticket. The librarian then shreds the photograph and frees the shelf space. If you walk away without handing back the ticket, the photograph sits there until the ticket expires.

!
Common mistake

Clearing only in the success path of the program. If an error occurs halfway, the scroll is abandoned. Put the clear call in a cleanup step that always runs, such as a finally block or an equivalent in your language.

9Internal Working: Search Contexts, Readers and Bookmarks

Now let us look inside a shard to see how the frozen view really works.

Each shard is a Lucene index made of immutable segments. When the initial scroll search reaches a shard, the shard creates a search context. Inside it is a reader that points at the exact list of segments that existed at that moment, along with the record of which documents in those segments were alive. This reader is the frozen view.

Because segments never change once written, holding on to a set of segments is a cheap and elegant way to freeze data. Nothing needs to be copied. The shard simply refuses to delete those segment files while a reader still uses them. New documents go into new segments that the frozen reader does not know about, so the scroll never sees them.

graph TD
    A["Scroll starts"] --> B["Shard creates search context"]
    B --> C["Reader pins segments A, B and C"]
    C --> D["Live index continues"]
    D --> E["New segment D appears, invisible to the scroll"]
    D --> F["Merge combines A and B into segment E"]
    F --> G["Old segments A and B stay on disk while the scroll needs them"]
    C --> H["Each batch continues from the bookmark inside the pinned view"]
        
FIG 4 — A scroll pins segments, so later merges cannot delete what the scroll still needs

How the bookmark works

Along with the reader, the search context stores the position reached so far for the chosen sort order. When the next batch is requested, the shard resumes after that position. It does not re-run the whole search from the beginning and discard the first hits. This is why a scroll’s cost per batch stays steady, unlike deep paging.

How the batches come together

For each batch, the coordinating node asks every shard for its next portion, merges the portions, keeps the best according to the sort order and returns exactly the requested batch size. Each shard advances only as far as the hits that were actually delivered, so nothing is lost or repeated between batches.

Simple Analogy

Imagine each wing of the library has its own clerk holding a numbered photograph of the wing’s cards. Each clerk remembers the last card handed over. When the researcher asks for the next tray, each clerk continues from that card, and the head librarian combines the results into one tray.

i
Key insight

The context is tied to a specific copy of each shard on a specific node. That is why a scroll cannot simply move to another node if the first one fails. The frozen view exists only where it was created.

10The Price of Freezing: Old Segments, Disk and File Handles

Holding a frozen view is not free, and the cost appears in three places.

Elasticsearch continually merges small segments into larger ones in the background, and afterwards deletes the old small ones. A scroll disturbs this tidy routine. Any segment still needed by an open scroll cannot be deleted, even if a merge has already replaced it. The old files stay on disk until the scroll finishes.

Cost 1

Extra disk space

Both the old pinned segments and the newly merged ones exist at the same time. On a busy index with long scrolls, this can add up to a large amount of temporary space.

Cost 2

More open file handles

Every segment file that is kept alive occupies an operating system file handle. Many long scrolls on many shards can approach the limit.

Cost 3

Memory for contexts

Each context holds its reader, and some memory structures, on the heap and in caches, for as long as it lives.

Cost 4

Deleted data lingers

Documents deleted after the scroll started still occupy pinned segments, so space from deletes is not returned until the scroll ends.

Simple Analogy

A cleaner is about to throw out old cardboard boxes after repacking their contents into bigger boxes. But a researcher is still reading from a photograph of the old boxes. The cleaner must wait, so both old and new boxes crowd the storeroom.

Why this matters most on busy indices

If an index is nearly static, such as yesterday’s log index, a scroll pins segments that will not change anyway, and the extra cost is small. If the index is busy, with constant indexing and heavy merging, a long scroll can hold a large amount of obsolete data. The longer the scroll runs and the more churn the index sees, the greater the temporary footprint.

!
Watch out

A forgotten scroll on a busy index can quietly keep gigabytes of obsolete segments alive. If a disk is filling faster than expected, check the number of open scroll contexts among the first suspects.

i
Operations tip

Elasticsearch documentation asks operators to give nodes ample free file handles, and to monitor the number of open contexts. Both are cheap habits that prevent scroll-related surprises.

11Limits and Settings You Should Know

A few guard rails protect the cluster from runaway scrolls.

SettingWhat it controlsTypical default
search.max_open_scroll_contextThe maximum number of scroll contexts open at the same time on a node500
search.max_keep_aliveThe longest keep-alive a request may ask for24 hours
search.default_keep_aliveThe keep-alive used when a request does not specify one5 minutes
index.max_result_windowThe largest allowed batch size, and the depth limit of ordinary paging10,000
index.max_slices_per_scrollThe largest number of slices allowed in a sliced scroll1,024
!
Version note

Defaults can change between versions, and some settings are dynamic while others are static. Always confirm the current names and defaults in the documentation for your release before changing anything.

What happens when limits are hit

If too many scrolls are open on a node, new scroll requests are rejected with an error stating that too many scroll contexts are open. The message names the limit. This usually means that scrolls are being started without being cleared, or that many parallel jobs are running at once. Raising the limit is possible, but the better fix is usually to find out why so many contexts are needed and to clear them properly.

If the requested keep-alive is greater than the maximum, the request is rejected as invalid, with a message that points to the maximum setting. If the batch size is above the result window, the request fails with a message about batch size. All three errors are clear and quick to diagnose once you know the settings behind them.

Simple Analogy

A reading room has a limited number of tables, and each visitor may reserve one for a limited time. If every table is reserved, the next visitor is turned away with a polite note, and the fix is to encourage people to return their tickets.

i
Practical tip

Before raising any limit, look at the current number of open contexts using the node statistics. If the number is far below the limit during normal operation and spikes only during broken jobs, fix the jobs instead.

12Sliced Scroll: Reading in Parallel

One reader is sometimes too slow. Slicing lets many readers share the work.

A single scroll walks through results one batch after another, with only one client busy at a time. For very large jobs, you can split the work into slices. Each slice is an independent scroll that covers a separate portion of the documents. You give every slice a number, from zero up to the total number of slices minus one, and the total count. Different workers can then read different slices at the same time.

graph LR
    Q["One query and one frozen view idea"] --> S0["Slice 0 with its own scroll ID"]
    Q --> S1["Slice 1 with its own scroll ID"]
    Q --> S2["Slice 2 with its own scroll ID"]
    S0 --> W0["Worker 0"]
    S1 --> W1["Worker 1"]
    S2 --> W2["Worker 2"]
    W0 --> R["Together they read every matching document once"]
    W1 --> R
    W2 --> R
        
FIG 5 — A sliced scroll gives each worker its own share of the results

How documents are divided

By default, Elasticsearch decides which slice a document belongs to using a hash of its identifier, spread evenly. Each document falls into exactly one slice, so together the slices cover all matches without overlap. You may also name a numeric field with doc values, and the slice is chosen from that field’s value instead. That can be more efficient in some cases, but the field must exist in all documents and should hold a single value each.

ChoiceAdvice
Number of slicesStart with a number equal to or below the number of shards, so each slice maps neatly to shards
More slices than shardsPossible, but the slice filter can be slow at first, so measure carefully
Custom field for slicingUse a numeric field with doc values, with one value per document
Keep-alive per sliceEach slice needs its own keep-alive refreshed with its own requests
ClearingClear every slice’s scroll ID when finished
Simple Analogy

Instead of one researcher reading a huge catalogue photograph tray by tray, three researchers each take every third card. They work at the same time, and together they see every card once.

!
Watch out

Slices multiply the resources held on the cluster. Ten slices means ten sets of contexts and ten streams of requests. Increase parallelism only as far as the cluster and the destination system can comfortably handle.

13Scroll Versus Search After With a Point in Time

Elastic now recommends a newer pair of features for many jobs that once used scroll.

A point in time, often shortened to PIT, is a lightweight handle that freezes a view of one or more indices for a chosen period, similar to the frozen view of a scroll. Search after is a way of continuing a search by giving the sort values of the last hit you saw. When you combine them, you get stable paging that does not need a heavy per-request cursor.

AspectScrollPoint in time with search after
Frozen viewYes, held in each search contextYes, held by the point in time
Where the position livesInside the cluster, in the search contextIn your client, as the last sort values
Arbitrary sort orderSupported, but the natural order is fastestSupported, with a tiebreaker to keep order stable
Random access or restartNot possible, you can only move forwardYou can resume from any sort values you saved
Parallel readingSliced scrollSlicing is also supported in modern versions with a point in time
Documentation recommendationNo longer recommended for deep pagingRecommended for deep paging with a stable view
Common uses todayInternal operations and older integrationsNew export and paging code

Why the newer way is often better

With search after, your program stores the sort values of the last hit. If the program crashes, it can restart from those values instead of losing its place. The cluster holds less per-request state, and the cost of keeping the frozen view alive is lower. Search after is also friendlier to user-facing paging, where the user moves forward and backward.

When scroll still makes sense

Scroll remains valid and is very common in existing tools. It is simple to reason about, it has a natural fit for reading everything once, and many client libraries offer helper functions that wrap it. If your Elasticsearch version or your client library does not yet support the newer approach, scroll is a safe choice.

Simple Analogy

Scroll is a librarian who remembers exactly where you stopped. Search after is you writing down the last card number you read. If the librarian goes home sick, your own note still tells you where to resume.

i
Decision shortcut

For new code, prefer a point in time with search after. For maintaining existing scroll-based tools, keep them working and plan to migrate when convenient, checking your version’s documentation for details.

14Choosing the Right Tool for Reading Results

Different reading jobs need different tools.

Your jobBest fitReason
Show the first few pages of results to a userOrdinary from and sizeSimple, stateless, cheap for shallow depths
Let a user page deeply with a stable viewPoint in time and search afterStable, lightweight and restartable
Export all matching documents oncePoint in time with search after, or scrollReads everything from a consistent view
Copy an index to another indexThe reindex APIBuilt for the job, handles batches and slicing for you
Change many documents by a queryUpdate by queryUses a consistent view and batching internally
Remove many documents by a queryDelete by querySame reasons
Only summaries, such as counts and totalsAggregationsNo need to read every document
Real-time updates to a live feedStream or poll with fresh searchesA frozen view would hide new data

Ask whether you need the documents at all

Many scroll jobs read millions of documents only to compute a total, an average or a top-ten list. Aggregations do that work inside the cluster and return a tiny answer. Before writing an export loop, check whether a single aggregation can give you what you need.

!
Common misconception

Scroll is not meant for serving real-time user requests. A user clicking through result pages should not each hold a scroll open. The resources held per scroll make that approach expensive and fragile at scale.

“Use scroll to move data, not to browse it.”

15Scroll Inside Other Elasticsearch Features

You may be using scrolls without knowing it.

Several built-in features of Elasticsearch are, at heart, a loop that scrolls through the matching documents and does something with each batch. Knowing this helps you understand their behaviour, their resource use and the settings that affect them.

Feature 1

Reindex

Reads documents from a source index in batches and writes them into a destination. It exposes a batch size setting and supports slices to speed up the copying.

Feature 2

Update by query

Finds documents that match a query and rewrites each one, working through batches taken from a consistent view.

Feature 3

Delete by query

Finds matching documents and deletes them batch by batch. Because it relies on a consistent view, documents that change while it runs may cause version conflicts.

Feature 4

Client helper functions

Official client libraries include helpers that wrap the scroll loop, handling scroll IDs, refreshing the keep-alive and clearing at the end.

Feature 5

Data shippers and connectors

Tools that copy data out of Elasticsearch into other systems often use scrolling to read whole indices safely.

Feature 6

Analytics and machine learning exports

Jobs that read large sets of documents for training or reporting may use scroll-style reading to gather them.

Simple Analogy

A removal firm uses a truck and a checklist for every house it empties. Whether you call the job “moving”, “clearing out” or “storing”, the same truck-and-checklist routine sits underneath. Reindex and the by-query APIs are such jobs, and the scroll is their truck and checklist.

What this means for you

When a long reindex or update by query runs, it holds frozen views on the source index, with all the disk and file handle costs discussed earlier. This is one reason why large reindex jobs are best run during quieter periods, and why their duration matters. It also explains version conflicts in update and delete by query: the frozen view may contain an older version of a document than the live index now holds.

i
Practical tip

Prefer these built-in APIs over writing your own copy loop when they fit your task. They already handle batching, retries, throttling and slicing, and they are maintained together with the rest of the product.

16Consistency: What You Will and Will Not See

The frozen view gives strong guarantees, and a few surprises.

What the scroll guarantees

Every document that was searchable at the moment the scroll began, and matches your query, will be delivered exactly once. No document appears twice, and none is skipped because of changes made after the start. This is the property that makes scrolls trustworthy for exports and migrations.

What the scroll will not show

Event after the scroll startedDoes the scroll see it?Explanation
A new document is indexedNoIt lives in segments the frozen view does not know about
A document is updatedNo, the scroll returns the old versionThe old version remains in the pinned view
A document is deletedNo, the scroll still returns itThe deletion marker is not part of the frozen view
A document was indexed but not yet refreshed at the startNoOnly searchable documents are included in the view
The index is deletedThe scroll may failThe underlying data disappears with the index
sequenceDiagram
    participant W as Writer
    participant I as Live Index
    participant S as Scroll View
    participant R as Reader
    Note over S: Scroll starts, view frozen with documents 1 to 5
    W->>I: Add document 6
    W->>I: Update document 2
    W->>I: Delete document 4
    R->>S: Request next batch
    S-->>R: Documents from the frozen view only
    Note over R: Reader sees old document 2 and document 4, and never sees document 6
        
FIG 6 — Changes after the start are invisible to the scroll

The difference between consistent and current

The scroll is consistent, but not current. Its answers are perfectly repeatable, and they describe the index at one moment. They may be minutes or hours out of date by the time you finish. If your task needs the freshest data, such as syncing a live system, you must plan a follow-up pass to catch changes made during the scroll, for example by reading the documents whose timestamps are newer than the scroll’s start.

Simple Analogy

A photograph of a busy street is always accurate for the moment it was taken. It never changes, but it also cannot tell you that a bus arrived later. For an export, that is exactly what you want. For live monitoring, it is exactly what you do not want.

!
Watch out

Using a scroll to keep two systems in sync without a plan for changes made during the scroll leaves gaps. Record the start time, then catch up on later changes in a second pass.

17Failure Behaviour: Restarts, Timeouts and Lost Contexts

Because scrolls are stateful, some failures cannot be repaired by simply retrying.

The search context lives in the memory of the node that holds the shard copy. It is not saved to disk and it is not copied to other nodes. If that node restarts, crashes, or if the shard is moved away, the context disappears. The next scroll request that refers to it fails with an error saying that no search context was found for the given identifier.

EventEffect on the scrollWhat to do
Keep-alive expires between requestsThe context is removed, the next request failsStart a new scroll, and increase the keep-alive if batches take long
A node holding a shard copy restartsIts contexts are lostStart again, ideally from a saved position if you track one
A shard relocates to another nodeThe old context is not carried overAvoid long scrolls during rebalancing, or be ready to restart
Client crashesContexts remain until the keep-alive expiresUse short keep-alives to release resources quickly
Network glitch on one requestThe request may be safe to retryRetry with the same scroll ID, with limits
Too many open contexts on a nodeNew scrolls are rejectedClear finished scrolls and review parallel jobs

Designing for restartability

Long export jobs should expect to fail sometimes. A robust design records progress outside the cluster, for example the last value of a sort field that was safely written, and knows how to begin a new scroll from that point using a range query. That way, a lost context costs a few minutes of work, not the whole job.

Simple Analogy

If the librarian holding your photograph goes home sick, the photograph goes with them. A researcher who kept notes of the last card number copied can ask a new librarian to take a fresh photograph and continue from the noted card.

i
Practical tip

For jobs that run longer than a few minutes, sort by a stable field, save checkpoints, and make every write on the destination side idempotent. Then restarting from a checkpoint is safe even if a few documents are read twice.

18Real-World Examples

The same technique serves very different teams.

Nightly compliance export

A bank must send all transaction records of the previous day to an archive system. A job scrolls through yesterday’s index, which no longer receives writes, writes each batch to files and uploads them. Because the index is static, extra disk and merge costs are small, and the consistent view gives an exact copy.

Rebuilding an index with a new mapping

A retailer needs to change how a field is mapped. Since mappings of existing fields cannot be changed in place, the team creates a new index and copies all documents into it using the reindex API, which scrolls through the old index in batches, optionally sliced for speed.

Feeding a data warehouse

An analytics team loads Elasticsearch documents into a data warehouse each week. A sliced scroll with several workers reads different slices in parallel, and each worker saves checkpoints. The team records the start time so a follow-up pass can catch documents changed during the run.

Machine learning training data

A data science team needs millions of labelled documents for training. They read them with a scroll, sorted in natural order for speed, and stream them into their training pipeline. They ask only for the fields they need to keep the batches small.

Bulk clean-up after a bad ingest

A faulty pipeline added malformed documents to an index. An operator uses delete by query, which scrolls through the matches and deletes them in batches. They run it in a quiet period and watch the number of open contexts and the free disk space while it works.

Legacy tool that still uses scroll

An older reporting tool loops through search results with the scroll API. The team leaves it in place but adds proper clearing of contexts, sets a modest keep-alive, and plans to move it to the newer point-in-time approach at the next upgrade.

Exports
consistent copy of a static index
Reindex
batched copying with optional slices
Clean-up
by-query jobs on a frozen view

19Security and Compliance Considerations

A scroll ID is a key to a set of results, so treat it with care.

When security features are enabled in Elasticsearch, a scroll is tied to the user who created it. The cluster checks that scroll requests come from the same authenticated user as the initial search. A different user who somehow obtains the scroll ID should be refused. This protects results from being read by another account, but it is still wise to avoid leaking scroll IDs in logs or shared tools.

Control 1

Least privilege

Give export jobs a role that can read only the indices they need, and nothing that can write or administer.

Control 2

Document and field rules apply

Any document-level or field-level security on the user’s role is applied at the start of the scroll, so exports contain only what that user may see.

Control 3

Protect scroll IDs

Do not print scroll IDs into shared logs, tickets or chat messages. Treat them as short-lived credentials for reading data.

Control 4

Encrypt the export destination

A scroll may copy millions of records out of the cluster. Make sure the files or systems that receive them are encrypted and access-controlled.

!
Compliance risk

Bulk export is the moment when data most easily leaves its protected home. Keep an audit trail of who ran which export, when, and where the output went. Enable audit logging in Elasticsearch, and log the export job’s own actions too.

Frozen views and deletion promises

Because a scroll pins a snapshot, a document deleted for privacy reasons can still be delivered by a scroll that started before the deletion. If you have a policy that data must vanish immediately, be aware that an in-flight scroll may still hold it, and limit scroll duration accordingly. The segments holding it are also kept on disk until the scroll ends.

i
Operations tip

Run exports with dedicated service accounts, never with personal or administrator accounts. That keeps audit trails clear and limits the damage if credentials leak.

20Monitoring, Logging and Metrics

You should know how many scrolls are open before they cause trouble.

Elasticsearch reports scroll activity in its node and index statistics. A handful of numbers gives you a clear picture of whether scrolls are healthy, and they are easy to chart and alert on.

SignalWhere to see itWhat it tells you
Open search contextsNode stats for searchHow many frozen views are currently held, a direct indicator of leaks
Current scrollsNode and index search statsHow many scroll operations are running right now
Total scrolls and total scroll timeNode and index search statsHow much scrolling has been done overall, and how long each takes on average
Segment count and deleted documentsSegments and cat APIsWhether pinned segments are inflating storage
Disk free spaceCat allocation and host metricsWhether scrolls plus merges are consuming too much room
Open file descriptorsNode stats for the processWhether handles are approaching the operating system limit
Rejections and errorsClient logs and cluster logsToo many contexts, missing contexts or invalid keep-alive requests
Slow search logsIndex slow log settingsWhich scroll batches are slow, and on which shards

Alerts worth having

Alert 1

Open contexts high

Warn when open contexts on a node exceed a comfortable fraction of the configured maximum.

Alert 2

Contexts not falling

Warn when the count stays high for a long time with no matching jobs, a sign of leaked scrolls.

Alert 3

Low disk during scrolls

Warn when free space drops while scrolls are running on busy indices.

Alert 4

Repeated missing context errors

Warn when clients report lost contexts often, which suggests keep-alive values that are too short.

i
Operations tip

Add scroll statistics to the same dashboard as disk space and file descriptors. Trouble from scrolls is usually a combination of all three, and seeing them side by side saves hours of guessing.

21Design Patterns and Anti-Patterns

Habits that keep scrolls safe, and traps that catch careful teams.

Patterns worth copying

Pattern 1

Short keep-alive, refreshed every batch

Use a modest keep-alive, send it with each request, and let crashes release resources quickly.

Pattern 2

Always clear in a cleanup step

Place the clear request in a block that runs on success and on failure.

Pattern 3

Natural order for exports

Sort by the natural document order when order does not matter, and sort later in your own system if needed.

Pattern 4

Checkpointed jobs

Record progress outside the cluster so that a lost context costs minutes, not hours.

Pattern 5

Scroll static indices

Schedule big reads on indices that no longer change, such as yesterday’s, so pinned segments cost little.

Pattern 6

Prefer built-in APIs

Use reindex, update by query and delete by query instead of custom loops when they fit the task.

Anti-patterns to avoid

ANTI-PATTERN-01 Avoid
Problem

A website opens a scroll for each visitor who views search results and keeps it open so that the visitor can click “next page” whenever they like.

Why It’s Harmful

Each visitor pins a frozen view on every shard, holding memory, file handles and disk. A busy day opens thousands of contexts, hits the limit and blocks other searches, while most visitors never return for a second page.

Correct Approach

Use ordinary paging for the first pages, and use search after, with a point in time when a stable view is needed. Reserve scroll for batch jobs.

ANTI-PATTERN-02 Avoid
Problem

A script never clears its scrolls and uses a keep-alive of several hours “to be safe”, then is run many times a day.

Why It’s Harmful

Contexts pile up, each holding pinned segments. Disk usage climbs, file handles run short, and eventually new scrolls are rejected because the maximum is reached.

Correct Approach

Use a short keep-alive refreshed with every batch, and clear the scroll when finished, including when errors occur.

ANTI-PATTERN-03 Avoid
Problem

A team scrolls through every document to compute totals and averages in application code.

Why It’s Harmful

Millions of documents travel over the network only to be reduced to a few numbers. The cluster and the client both do far more work than needed, and a frozen view is held for the whole run.

Correct Approach

Use aggregations, which compute summaries inside the cluster and return a tiny result.

ANTI-PATTERN-04 Avoid
Problem

An export job uses a huge number of slices and a very large batch size to finish faster, and runs on the busiest index during peak hours.

Why It’s Harmful

Many parallel contexts and large batches strain memory and disk, compete with live searches and indexing, and can trigger rejections or slow the whole cluster for users.

Correct Approach

Choose a moderate number of slices, size batches for the documents involved, and run heavy exports during quiet hours on static indices where possible.

22Advantages and Trade-offs

An honest balance sheet for the scroll API.

Advantages

  • Reads very large result sets in manageable batches.
  • Gives a consistent view, so every document is delivered exactly once.
  • Cost per batch stays steady, no matter how deep you are.
  • Fastest when sorted by natural order, ideal for exports and copies.
  • Supports slicing for parallel reading by several workers.
  • Widely supported by clients, tools and built-in features.

Disadvantages / Trade-offs

  • Holds resources in the cluster: memory, file handles and pinned segments.
  • Is stateful, so node restarts and shard moves can destroy the context.
  • Shows old data, since changes after the start are invisible.
  • Cannot go backward or jump, only forward from the current position.
  • Unsuitable for real-time, user-facing paging.
  • No longer the recommended approach for deep paging in current documentation.

23Best Practices and Common Mistakes

A checklist to keep next to any export script.

Best practices

1

Ask whether you need scroll at all

Check whether an aggregation, a built-in API or a point-in-time approach would serve better.

2

Keep the keep-alive modest

Long enough for one batch plus a safety margin, and refreshed on every request.

3

Fetch only what you need

Use source filtering to request specific fields, making batches smaller and faster.

4

Always use the latest scroll ID

Update your variable after every response, and send the ID in the request body.

5

Clear when finished

Release the frozen view immediately, in a cleanup step that runs even on errors.

6

Plan for failure

Save checkpoints and make the destination writes safe to repeat.

7

Monitor open contexts

Track the number of open contexts, disk space and file handles during and after big jobs.

Common mistakes

Treating the keep-alive as total job time

Setting a keep-alive to cover the entire export rather than the time between batches, and so holding resources far longer than needed.

Reusing an old scroll ID

Sending the very first scroll ID in every request instead of the most recent one, which can produce errors or repeated batches.

Ignoring the end condition

Failing to stop when a batch is empty, or stopping early on a short batch when more batches may follow.

Expecting fresh data

Being surprised that documents added during the scroll never appear. The scroll shows the state at its start.

Scrolling a busy index at peak time

Running heavy long scrolls when the index is under constant writes, which pins a lot of obsolete data.

24Troubleshooting Scroll Problems

Match the symptom to the likely cause and check the simplest explanation first.

SymptomLikely causeWhat to check
Error saying no search context was foundKeep-alive expired, node restarted or shard movedBatch processing time versus keep-alive, node restarts and relocations
Error about too many scroll contextsScrolls are not being cleared, or too many jobs run at onceOpen context counts, job schedules and clear calls
Error about keep-alive being too largeRequested time exceeds the configured maximumThe maximum keep-alive setting and the value your client sends
Error about batch size being too largeSize is above the result windowThe index result window setting and the size parameter
Disk usage grows during an exportPinned old segments on a busy indexSegment counts, merge activity and duration of scrolls
Documents added later are missingFrozen view excludes changes after the startExpected behaviour, plan a catch-up pass if needed
Scroll is slowSorting by score or field, huge documents or slow client processingSort choice, source filtering and time spent between requests
Web address too long errorLong scroll ID sent in the URLSend the scroll ID in the request body
Another user cannot continue a scrollScroll is bound to the user that created itWhich credentials each request uses

A calm routine

First, read the exact error message, because most scroll errors name their cause and the setting behind it. Second, look at the number of open contexts and the free disk space on the nodes involved. Third, compare the keep-alive with the real time between requests. Fourth, check whether nodes restarted or shards moved during the job. These four checks explain the vast majority of scroll problems.

!
Emergency measure

Clearing all scrolls can free resources quickly, but it will also break other people’s running jobs. Use it only when the cluster is in real trouble, and tell the affected teams afterwards.

25Frequently Asked Questions

Short answers to doubts that come up again and again.

Q1What is the scroll API in one sentence?

It lets you run one search and read its results in many consecutive batches from a consistent snapshot of the data, using a scroll ID to mark your position.

Q2Is scroll meant for user-facing pagination?

No. It is designed for batch processing such as exports and reindexing. User-facing pages should use ordinary paging or search after with a point in time.

Q3Does the keep-alive cover the whole job?

No. It only needs to cover the time between one request and the next. Each request refreshes it.

Q4Will documents added during the scroll appear in the results?

No. The scroll shows the index as it was when the scroll started. Later additions, updates and deletions are not visible to it.

Q5Do I have to clear a scroll?

It will expire on its own after the keep-alive, but clearing it as soon as you finish frees memory, file handles and pinned disk space at once, so you should always clear it.

Q6Why is sorting by the natural order faster?

Each shard can simply walk through its documents without comparing scores or field values, so batches are cheaper to produce.

Q7What is a sliced scroll?

A way of dividing one scroll into several independent slices, each with its own scroll ID, so that different workers can read different portions in parallel.

Q8What happens if a node restarts during my scroll?

The contexts held by that node are lost, and your next request fails with a missing search context error. You must begin again, ideally from a checkpoint you saved.

Q9How is scroll different from search after with a point in time?

Both provide a stable view. With scroll the cluster remembers your position in a search context. With search after your client remembers the last sort values, which makes restarting easier and the cluster’s load lighter. Current documentation recommends the latter for deep paging.

Q10Why does my disk fill up during a long scroll?

Segments still needed by the scroll cannot be deleted after merges, so old and new segments coexist. This is worst on busy indices with long scrolls.

Q11Can someone else use my scroll ID?

With security enabled, the scroll is bound to the authenticated user who created it, so other users should be refused. Still, avoid exposing scroll IDs in logs or shared tools.

Q12Do reindex and delete by query use scrolling?

Yes, they read documents in batches from a consistent view in a similar way, which is why their behaviour, resource use and conflicts resemble those of a scroll.

26Summary and Key Takeaways

The Scroll API lets you read a very large result set in steady batches from a frozen view of the data. You open it with a search that carries a keep-alive time, receive a scroll ID, come back for batch after batch, and clear it when finished. Inside the cluster, each shard holds a search context that pins the segments of the frozen view and remembers your position, which keeps every batch cheap but costs memory, file handles and disk space until the scroll ends. It is ideal for exports, reindexing and batch clean-ups, poorly suited to real-time paging, and today the documentation prefers a point in time with search after for deep paging. Use it with short keep-alives, natural ordering, proper clearing, monitoring and a plan for failure.

Key Takeaways

  • Batches from a frozen view — a scroll reads results in consecutive batches from a snapshot of the index taken when the scroll began.
  • The scroll ID is your bookmark — always send the latest ID, in the request body, and stop when a batch comes back empty.
  • Keep-alive is per request — it must cover the time between batches, not the whole job, and each request refreshes it.
  • Stateful means costly — open contexts pin segments and hold memory and file handles, so clear scrolls promptly and watch disk and open contexts.
  • Sort by natural order and slice for speed — use the natural document order for exports, and a moderate number of slices for parallel reading.
  • Consistent, not current — changes after the start are invisible, and failures such as restarts destroy the context, so checkpoint long jobs.
  • Prefer the right tool — use aggregations for summaries, built-in APIs for copying and clean-up, and a point in time with search after for new deep paging code.