Elasticsearch Reindex
ElasticOfficialCreated by elastic
- Skill
- Tool integration
- Software development
- Apache-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured workflow for copying or migrating data between Elasticsearch indices. It covers critical aspects of the reindex process, including environment verification, destination preparation, performance tuning, and task management. It emphasizes best practices such as using asynchronous task execution for large jobs, applying filters to limit data scope, and verifying results through document counts. The skill is designed to help users navigate the differences between self-managed, Elastic Cloud Hosted, and Serverless deployment environments.
What it does
- Guides the preparation of destination indices with correct mappings and settings.
- Facilitates local and remote cluster data migration.
- Provides methods for filtering data subsets during the reindex process.
- Supports performance optimization via slicing, throttling, and batch sizing.
- Enables asynchronous task tracking and management.
- Ensures data integrity through post-reindex count verification.
When to use it
- When you need to change field mappings or analyzers on an existing index.
- When migrating data between different Elasticsearch clusters.
- When you need to transform data during the copy process.
- When you need to copy a specific subset of data based on time ranges or other filters.
- When consolidating indices or data streams.
Advantages
- Reduces risk of partial failures by enforcing explicit destination preparation.
- Improves performance for large datasets using parallel slicing and throttling.
- Provides clear guidance on deployment-specific constraints.
- Minimizes downtime by supporting alias swaps and asynchronous background tasks.
Usage examples
- “How do I reindex a large index named events into events-v2 while throttling the speed?”
- The agent will provide the POST /_reindex command with slices=auto and a specified requests_per_second parameter to manage cluster load.
- “I need to migrate only the logs from January 2025 from my metrics index.”
- The agent will guide you to create a destination index and use a source query with a range filter on the @timestamp field.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/elastic/elasticsearch-reindex/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip elasticsearch-reindex.zip -d .agents/skills
Documentation by elastic
Elasticsearch Reindex
Copy documents from source indices or data streams to a destination using POST /_reindex. An expert reindex workflow
prepares the destination explicitly, chooses local versus remote execution, filters at the source when only a subset is
needed, runs long copies asynchronously, tracks the task to completion, and verifies the destination document count
before reporting results.
<!-- begin-partial: preamble -->
Environment Configuration
This skill executes Elasticsearch operations through the elastic CLI. If the
elastic CLI is not installed, tell the user what it is needed for. Do
not guess credentials, call the HTTP API directly, or attempt other workarounds.
This skill references operations in HTTP-shorthand form (e.g., GET /, GET /_cat/indices, GET /{index}/_mapping,
GET /{index}/_settings/index.mode, POST /_query). The Operations table at the end of this document
maps each shorthand to the equivalent elastic CLI command — always use the CLI rather than calling the HTTP API
directly.
<!-- end-partial: preamble -->
Process
Confirm connectivity and deployment type. Call
GET /. Readbuild_flavorandversion.numberto know whether shard, replica, and cluster-settings APIs are available (Serverless manages shards/replicas internally and blocks most_cluster/*APIs). The decision: continue only when the cluster is reachable. If the call fails, stop — do not guess endpoints or credentials.Decide local versus remote reindex. Compare where the source and destination live.
Same cluster — use local reindex:
source.indexanddest.indexonly. Do not addsource.remotewhen both indices are on the cluster you are connected to.Different cluster — use reindex from remote: add
source.remotewith the remote cluster URL and credentials. Remote reindex does not support slicing; compensate with query-based partitioning (date ranges, term filters) across parallel requests. Confirm the remote host is allowlisted on Self-Managed / ECH (reindex.remote.whitelistin cluster config); Serverless manages allowlisting internally (ECH remotes only, Tech Preview).
Data needed: source index name(s), destination index name, and whether they share a cluster.
Inspect the source — never guess field names or counts. Call
GET /{source}/_mappingto ground field names and types. CallGET /{source}/_count(orGET /_cat/count/{source}?h=counton Self-Managed / ECH) to learn how many documents exist.The decision: full copy versus filtered subset.
Full copy — omit
source.query(match-all behavior).Filtered subset — add
source.querywith Query DSL. For time ranges, use arangefilter on the timestamp field (commonly@timestamp), e.g."gte": "2025-01-01", "lt": "2025-02-01"for January 2025. Do not run a full-index copy when the user asked for a date range or other filter.
Data needed: the user's filter criteria and the mapping-confirmed field names.
Prepare the destination index before copying.
_reindexdoes not copy mappings, shard counts, or analyzers. Create the destination with explicit settings and mappings derived from the source mapping viaPUT /{dest}.On Self-Managed / ECH: set
number_of_replicas: 0andrefresh_interval: "-1"on the destination during the copy for write throughput; restore production values afterward withPUT /{dest}/_settings.On Serverless: omit
number_of_shardsandnumber_of_replicas(managed by Elastic); you may setrefresh_interval: "-1"during the copy.For data stream destinations: ensure an index template with
data_stream: {}exists, create the data stream, and setdest.op_typeto"create"(append-only).
The decision: create/prepare the target rather than relying on auto-creation with dynamic mapping. Wrong or missing mappings cause partial failures or silent type coercion.
Data needed: destination name, corrected or compatible mappings, and deployment-specific settings constraints.
Build and submit the reindex request. Call
POST /_reindex?wait_for_completion=falsefor any copy that may take more than a few seconds or when the user says the index is large — the response returns a task id immediately instead of blocking.Request body essentials:
source.index— source index or data stream (correct name, not reversed withdest.index).dest.index— prepared destination from step 4.source.query— include only when step 3 chose a filtered subset.conflicts: "proceed"— when retrying a partially complete reindex.Optional tuning:
source.size(batch size),requests_per_second(throttle),slices=autoon local reindex only (parallelize per primary shard — never for remote),scroll(increase keep-alive on slow clusters),max_docs(test runs),script(transform),dest.pipeline(ingest enrichment).
Example filtered subset (January 2025 only):
{ "source": { "index": "eval-reindex-src", "query": { "range": { "@timestamp": { "gte": "2025-01-01", "lt": "2025-02-01" } } } }, "dest": { "index": "eval-reindex-jan" } }Do not reach for
_split,_shrink, or snapshot/restore when the task is a filtered subset copy or a straight document migration — those APIs solve different problems.Track the task to completion. Store the task id from the reindex response. Poll
GET /_tasks/{task_id}untilcompletedistrue. Readstatus.total,status.created, andresponse.failures. On Self-Managed / ECH you may also list active reindex tasks withGET /_tasks?actions=*reindex&detailed; on Serverless, query by task id only (list/cancel are not available). Adjust throttling mid-flight withPOST /_reindex/{task_id}/_rethrottle?requests_per_second=Nwithout canceling.Verify and report the destination count. Call
GET /{dest}/_count(works on all deployment types). On Self-Managed / ECH you may also useGET /_cat/count/{dest}?h=count. Compare source filter expectations to the destination count. Report the exact count from the destination — do not estimate or guess.After a successful full copy, restore production settings on the destination with
PUT /{dest}/_settings(replicas and refresh interval on Self-Managed / ECH; refresh interval only on Serverless).
Deployment constraints
| Capability | Self-Managed / ECH | Serverless |
|---|---|---|
| Local reindex | Full support | Full support |
| Reindex from remote | Full support | Tech Preview — ECH remotes only |
number_of_shards/replicas | User-configurable | Managed — omit on index creation |
slices=auto (local only) | Supported | Supported for local reindex |
GET /_cat/count/{index} | Supported | Not available — use GET /{index}/_count |
GET /_tasks (list/cancel) | Full | Get by task id only |
PUT /_cluster/settings | Supported | Blocked |
_split / _shrink | Supported | Not available |
Consider alternatives first
Runtime fields — fix field-type mismatches or add computed fields without reindexing when stored values need not change.
Aliases — redirect queries transparently; combine with reindex for zero-downtime mapping changes.
Snapshot and restore (Self-Managed / ECH) — faster whole-index transfer when no transformation is needed.
See the decision tree in references/patterns.md.
Reference material
API parameter reference — full
POST /_reindexbody and query parametersMulti-step patterns — mapping changes, remote migration, merge, ingest pipeline, performance
Tuning — batch size (
source.size), timestamps, versioningTroubleshooting — mapping conflicts, scroll timeouts, count mismatches
Examples
"Copy logs-2024 into a new index with a corrected mapping" — create the destination first, then reindex:
POST /_reindex
{ "source": { "index": "logs-2024" }, "dest": { "index": "logs-2024-v2" } }"Reindex a large index in parallel and throttle it" — slice automatically and cap the request rate:
POST /_reindex?slices=auto&requests_per_second=2000
{ "source": { "index": "events" }, "dest": { "index": "events-v2" } }"Migrate only recent documents" — filter the source with a query:
POST /_reindex
{
"source": { "index": "metrics", "query": { "range": { "@timestamp": { "gte": "now-30d" } } } },
"dest": { "index": "metrics-recent" }
}Guidelines
Confirm deployment type first. Call
GET /and readbuild_flavor; shard, replica, cluster-settings, and task APIs differ between Self-Managed / ECH and Serverless (see Deployment constraints).Prefer an alternative when it fits. Runtime fields, aliases, or snapshot-and-restore often avoid a full reindex.
Tune the destination for the copy. On Self-Managed / ECH set
number_of_replicas: 0andrefresh_interval: "-1"during the copy, then restore production settings afterward; on Serverless these are managed.Parallelize large copies. Use
slices=autofor local reindex and throttle withrequests_per_secondto protect the cluster.Run big jobs asynchronously. Submit with
wait_for_completion=falseand poll the task instead of blocking.Verify by count. Compare the source filter expectation to the exact destination
GET /{dest}/_count— never estimate.
Operations
| HTTP API (shorthand) | elastic CLI command |
|---|---|
GET / | elastic es info |
GET /{index}/_mapping | elastic es indices get-mapping --index '<index>' |
GET /{index}/_count | elastic es count --index '<index>' |
GET /_cat/count/{index}?h=count | elastic es cat count --index '<index>' --h count |
PUT /{index} | elastic es indices create --index '<index>' --mappings '<json>' --settings '<json>' |
PUT /{index}/_settings | elastic es indices put-settings --index '<index>' --settings '<json>' |
POST /_reindex?wait_for_completion=false | elastic es reindex --wait-for-completion false --source '<json>' --dest '<json>' |
GET /_tasks/{task_id} | elastic es tasks get --task-id '<task_id>' |
GET /_tasks?actions=*reindex&detailed | elastic es tasks list --actions '*reindex' --detailed |
POST /_tasks/{task_id}/_cancel | elastic es tasks cancel --task-id '<task_id>' |
POST /_reindex/{task_id}/_rethrottle?requests_per_second=N | elastic es reindex-rethrottle --task-id '<task_id>' --requests-per-second <N> |
Files
- ATTRIBUTION.mdAdded by AutoGineer986 B
- LICENSELicence file added by AutoGineer11.1 KiB
- SKILL.md12.6 KiB
- references/api-reference.md14.2 KiB
- references/patterns.md15.5 KiB
- references/troubleshooting.md2.4 KiB
- references/tuning.md2.8 KiB
references/api-reference.md
Reindex API Reference
Complete parameter reference for POST /_reindex. See the main skill file for usage guidance and best
practices.
Endpoint
POST /_reindex
POST /_reindex?wait_for_completion=false
POST /_reindex?wait_for_completion=false&slices=autoQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
wait_for_completion | boolean | true | Set to false to return a task ID immediately. The reindex runs in the background and results are stored in .tasks. |
requests_per_second | float | -1 (unlimited) | Throttle indexing rate. Each batch pauses to maintain this rate. Set to -1 to disable. |
slices | integer or "auto" | 1 | Number of parallel slices. auto uses one slice per primary shard. Not supported for remote reindex. |
scroll | duration | 5m | Keep-alive for the scroll context used to read from the source. Increase for slow clusters. |
timeout | duration | — | Timeout for the entire operation when running synchronously. |
refresh | boolean | false | Refresh the destination index after the reindex completes. |
Request Body
Top-level fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
conflicts | string | No | "abort" | "abort" stops on the first version conflict. "proceed" skips conflicting documents and continues. Use "proceed" when retrying a partially-complete reindex. |
max_docs | integer | No | — | Maximum number of documents to reindex. Useful for testing a configuration on a small sample before running at full scale. |
script | object | No | — | Painless script to transform each document. See Script object. |
source object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
index | string or array | Yes | — | Source index name, alias, data stream, or list of indices. |
query | object | No | match_all | Query DSL to filter source documents. |
_source | array | No | all fields | List of fields to include in each document. |
size | integer | No | 1000 | Number of documents per scroll batch. Reduce for large documents; increase (up to ~5000) for small ones. |
slice | object | No | — | Manual slicing: { "id": 0, "max": 4 }. Prefer automatic slicing via the slices query parameter instead. |
remote | object | No | — | Remote cluster connection. See source.remote object. |
source.remote object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | — | Full URL including scheme, host, and port (e.g., https://remote:9200). An optional path prefix is supported (e.g., https://remote:9200/proxy). |
username | string | No | — | Basic auth username for the remote cluster. Supported for the remote regardless of where the reindex runs. Always use HTTPS when credentials are present. |
password | string | No | — | Basic auth password for the remote cluster. |
api_key | string | No | — | Base64-encoded API key. Preferred over basic auth. |
headers | object | No | — | Custom HTTP headers. Use { "Authorization": "ApiKey <value>" } as an alternative to api_key. |
socket_timeout | duration | No | 30s | Read timeout for each scroll request to the remote. Increase to 1m–5m for slow or congested networks. |
connect_timeout | duration | No | 30s | TCP connection timeout. Increase when the remote is behind a load balancer. |
dest object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
index | string | Yes | — | Destination index or data stream name. Create the index (or data stream via template) with explicit mappings before reindexing. When the destination is a data stream, set op_type to "create". |
op_type | string | No | "index" | "index" overwrites existing documents with the same _id. "create" only creates missing documents; use with "conflicts": "proceed" to skip conflicts. Required: set to "create" when the destination is a data stream (data streams are append-only). |
pipeline | string | No | — | Name of an ingest pipeline to apply to each document during indexing. |
routing | string | No | preserve | "keep" preserves source routing (default). "discard" sets routing to null. "=<value>" sets a fixed routing value. |
version_type | string | No | "internal" | "internal" ignores source version. "external" preserves source version and rejects older writes. Use "external" when synchronizing across clusters. |
Script object
| Field | Type | Description |
|---|---|---|
source | string | Painless script body. Access the document via ctx._source. Set ctx.op to "noop" or "delete" to skip or remove documents. Modify ctx._id, ctx._index, ctx._routing, and ctx._version as needed. |
lang | string | Script language. Default and recommended: "painless". |
params | object | Named parameters accessible inside the script. |
Response Body
Returned when the reindex completes synchronously or when fetching a completed task via GET _tasks/<task_id>.
| Field | Type | Description |
|---|---|---|
took | integer | Total time in milliseconds. |
timed_out | boolean | Whether the operation timed out. |
total | integer | Total documents processed (source-side). |
created | integer | Documents successfully created in the destination. |
updated | integer | Documents updated in the destination (same _id existed). |
deleted | integer | Documents deleted by a script setting ctx.op = "delete". |
batches | integer | Number of scroll batches pulled from the source. |
noops | integer | Documents skipped by a script setting ctx.op = "noop". |
version_conflicts | integer | Version conflicts encountered. Only non-zero when conflicts is "proceed". |
retries | object | { "bulk": N, "search": N } — retry counts for bulk and scroll operations. |
failures | array | List of per-document failure objects. Empty on full success. |
throttled_millis | integer | Total time spent waiting due to requests_per_second throttling. |
requests_per_second | float | Effective requests-per-second rate. |
Related APIs
| API | Endpoint | Purpose |
|---|---|---|
| Task status | GET _tasks/<task_id> | Monitor a running or completed reindex task. Works on all deployment types including Serverless. |
| List reindex tasks | GET _tasks?actions=*reindex&detailed | List all active reindex operations. Not available in Serverless — query by task ID instead. |
| Cancel task | POST _tasks/<task_id>/_cancel | Cancel a running reindex. Not available in Serverless — delete the destination index to stop. |
| Rethrottle | POST _reindex/<task_id>/_rethrottle?requests_per_second=N | Adjust throttling on a running reindex without canceling. |
| Count | GET _cat/count/<index>?h=count | Verify document count after reindex. Not available in Serverless — use GET /<index>/_count instead. |
reindex.remote.whitelist Setting
Configure in elasticsearch.yml on every coordinating node that may execute remote reindex requests. Accepts
comma-separated host:port pairs with wildcard support:
reindex.remote.whitelist: "remote-host:9200, 10.0.0.*:9200, localhost:*"This setting does not apply to Elastic Cloud Serverless — Serverless only permits remote reindex from Elastic Cloud Hosted clusters and manages the allowlist internally.
SSL Configuration for Remote Reindex
SSL settings for remote reindex connections are configured in elasticsearch.yml, not in the API request body. These
settings apply to Self-Managed only. On ECH, SSL is managed via the deployment configuration. On Serverless, remote
reindex SSL is managed internally by Elastic.
| Setting | Description |
|---|---|
reindex.ssl.certificate_authorities | List of PEM CA certificate paths. |
reindex.ssl.certificate | Client certificate path for mutual TLS. |
reindex.ssl.key | Client key path for mutual TLS. |
reindex.ssl.verification_mode | full (default), certificate, or none. Use none only in development. |
Secure settings (reindex.ssl.key_passphrase, reindex.ssl.truststore.*, reindex.ssl.keystore.*) are stored in the
Elasticsearch keystore via elasticsearch-keystore add.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
The author says: Elasticsearch 8.x or 9.x, self-managed, Elastic Cloud Hosted, or Elastic Cloud Serverless; local reindex works on all deployment types, while remote reindex requires host allowlisting on self-managed / Elastic Cloud Hosted (Serverless supports Elastic Cloud Hosted remotes only, Tech Preview). Requires the `elastic` CLI ≥ 0.2 with `stack es` support.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- elastic
- Publisher
- Elastic (Official)
- Source
- elastic/agent-skills · skills/elasticsearch/elasticsearch-reindex · commit 09d879d
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Also distributed in
- elastic/agent-skills
AutoGineer is not affiliated with or endorsed by elastic or Elastic.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download elasticsearch-reindex.zip