Moving search indices between Elasticsearch clusters is a fact of life when you're scaling infrastructure, migrating cloud providers, or consolidating legacy systems. The reindex API with remote source lets you pull documents directly from one cluster and ingest them into another—without staging data to disk or stopping your source system.
Today we're walking through reindex from remote in Elasticsearch & search engineering: how to set it up safely, throttle the operation to avoid overwhelming either cluster, and verify the migration succeeded.
Reindex API with a remote source
The Elasticsearch Reindex API supports a remote parameter that points to a source cluster. Instead of reading from a local index, your target cluster connects over HTTP and streams documents from the remote one. This is particularly useful when you want to consolidate two production clusters or migrate to a new infrastructure without maintaining temporary storage.
Here's a minimal example:
POST _reindex
{
"source": {
"remote": {
"host": "https://source-cluster.example.com:9200"
},
"index": "products"
},
"dest": {
"index": "products-migrated"
}
}
In this request, the target cluster (where you're running the reindex command) connects to the source cluster at source-cluster.example.com, reads from the products index, and writes documents to products-migrated on the local cluster.
You can also filter documents during the reindex, apply transformations, or change the destination index name. For instance, if you only want to migrate documents where status is "active":
POST _reindex
{
"source": {
"remote": {
"host": "https://source-cluster.example.com:9200"
},
"index": "products",
"query": {
"term": {
"status": "active"
}
}
},
"dest": {
"index": "products-migrated"
}
}
The remote reindex runs as a background task. You can check its progress with the tasks API or cancel it if needed.
Whitelist remote hosts
By default, Elasticsearch doesn't allow connections to arbitrary remote clusters for security reasons. You must explicitly whitelist the remote hosts in your target cluster's configuration.
Add the source cluster's address to elasticsearch.yml on your target cluster:
reindex.remote.whitelist: "source-cluster.example.com:9200"
If you have multiple source clusters, use a comma-separated list:
reindex.remote.whitelist: "source-cluster-1.example.com:9200,source-cluster-2.example.com:9200"
After updating the configuration, restart the nodes on your target cluster (rolling restart recommended). Until that restart happens, the reindex command will fail with an error like "host not whitelisted".
In a containerized or Kubernetes environment, you might set this via environment variables:
-E reindex.remote.whitelist=source-cluster.example.com:9200
Double-check that network connectivity exists between your two clusters. If they're behind firewalls or in different VPCs, open the necessary security group rules or network policies. Test with a simple curl from a target cluster node:
curl -u elastic:password https://source-cluster.example.com:9200/_cluster/health
If that succeeds, the whitelist configuration is correct.
Throttle to protect clusters
Reindexing from a remote source can be expensive: the target cluster fetches batches of documents, indexes them locally, and then requests more. Without throttling, this can spike CPU, memory, and network bandwidth on both clusters, potentially impacting production traffic.
The _reindex API offers two key throttling parameters:
slices: Split the reindex job across multiple parallel slices. Each slice processes a portion of the documents independently, which can speed up reindexing but also increases resource consumption.requests_per_second: Limit the rate at which the target cluster requests batches from the source. The default is unlimited.
Here's a conservative reindex that limits throughput and uses only a single slice:
POST _reindex
{
"source": {
"remote": {
"host": "https://source-cluster.example.com:9200"
},
"index": "products"
},
"dest": {
"index": "products-migrated"
},
"requests_per_second": 100,
"slices": 1
}
With requests_per_second: 100, the reindex will throttle itself to approximately 100 bulk requests per second. If each bulk request contains, say, 100 documents, you're indexing around 10,000 documents per second—a sustainable pace for most clusters.
If you want to parallelize the work across multiple slices:
POST _reindex?slices=auto&refresh
{
"source": {
"remote": {
"host": "https://source-cluster.example.com:9200"
},
"index": "products"
},
"dest": {
"index": "products-migrated"
},
"requests_per_second": 100
}
The slices=auto parameter tells Elasticsearch to pick an appropriate number of parallel slices based on the number of shards in the source index. This speeds up reindexing, but you'll want to monitor both clusters during the operation and be ready to cancel if CPU or disk I/O spikes too high.
For large indices (hundreds of millions of documents), we recommend starting with a small requests_per_second value (e.g., 50) and increasing it gradually as you observe the impact on your clusters. Use Kibana's monitoring dashboards or call the tasks API to watch progress and resource usage.
Verify document counts
After the reindex completes, always verify that the destination index has the expected number of documents. Mismatches can indicate dropped records, network issues, or filtering mistakes.
Get the document count for both indices:
GET products/_count
GET products-migrated/_count
If you applied a query filter during reindex, the destination count will naturally be lower. For example, if the source has 1,000,000 documents and you filtered for status="active" (which matched 950,000 documents), the destination should have 950,000:
GET products/_count?q=status:active
GET products-migrated/_count
Both should return the same result.
For a deeper check, sample a few documents from the source and destination and compare fields:
GET products/_search?size=5&sort=_id
GET products-migrated/_search?size=5&sort=_id
Spot-check that the field values, timestamps, and nested objects match. If you're migrating between different Elasticsearch versions, be aware that some field types (e.g., text vs. keyword) might behave differently if your destination mapping is less strict.
Finally, run a few representative queries on the destination index to confirm they return the expected results. If your application relies on aggregations, test those too:
GET products-migrated/_search
{
"aggs": {
"status_breakdown": {
"terms": {
"field": "status.keyword"
}
}
},
"size": 0
}
Compare the aggregation results with the source index to ensure data integrity.
Common mistakes
- Forgetting to whitelist the remote host. The reindex request will fail silently or with a cryptic "host not whitelisted" error. Always verify
reindex.remote.whitelistin your target cluster config and restart nodes after updating it. - Not throttling sufficiently. Unthrottled remote reindexes can saturate network bandwidth and exhaust the heap on your target cluster. Start conservatively and monitor before increasing
requests_per_second. - Reindexing the destination back into itself. If you mistakenly run reindex from remote when the source and destination are the same cluster and index, you'll create a infinite loop of documents. Always use a distinct destination index name.
- Ignoring authentication. If your source cluster requires credentials, include them in the remote host URL:
https://elastic:password@source-cluster.example.com:9200. For security, consider using an API key or a dedicated reindex user. - Not checking the reindex task status. A long-running reindex can fail partway through without obvious error messages. Poll the tasks API to confirm completion and watch for warnings.
Key takeaways
- Remote reindex pulls documents from a source cluster over HTTP and indexes them into a target cluster, avoiding intermediate storage.
- Whitelist the remote cluster's host in
elasticsearch.ymland restart the target cluster nodes before reindexing. - Use
requests_per_secondandslicesto control the load on both clusters; start conservative and monitor resource usage. - Verify document counts and sample data after reindex completes to catch data loss or corruption early.
- Always test the reindex on a non-production pair of clusters first, especially when crossing Elasticsearch versions.






Comments
Loading comments…