Server-side reindex
ServerReindex triggers an Elasticsearch _reindex with wait_for_completion=false and polls the task API until completion, yielding progress snapshots as an IAsyncEnumerable<ReindexProgress>.
Use server-side reindex when you want Elasticsearch to copy documents between indices entirely on the server. This is the fastest option when you don't need to transform documents in application code. For transformations beyond what ingest pipelines or painless scripts support, see client-side reindex.
The IncrementalSyncOrchestrator uses server-side reindex internally for its reindex-mode workflow. See incremental sync.
using Elastic.Ingest.Elasticsearch.Helpers;
var reindex = new ServerReindex(transport, new ServerReindexOptions
{
Source = "old-index",
Destination = "new-index",
});
await foreach (var progress in reindex.MonitorAsync())
{
Console.WriteLine($"Reindex {progress.FractionComplete:P0} -- " +
$"{progress.Created} created, {progress.Updated} updated");
}
Or run to completion in a single call:
var result = await reindex.RunAsync();
Console.WriteLine($"Done: {result.Created} created, {result.Updated} updated");
Instead of specifying index names as strings, you can provide ElasticsearchTypeContext instances. The source and destination indices are resolved from the type context's WriteAlias:
var reindex = new ServerReindex(transport, new ServerReindexOptions
{
SourceContext = sourceTypeContext,
DestinationContext = destTypeContext,
});
You can mix explicit strings and type contexts -- for example, providing Source as a string and DestinationContext as a type context. When Body is set, source/destination resolution is skipped.
Pass a JSON query to reindex a subset of documents:
var options = new ServerReindexOptions
{
Source = "old-index",
Destination = "new-index",
Query = """{"range":{"@timestamp":{"gte":"now-7d"}}}""",
};
Apply an ingest pipeline during reindex:
var options = new ServerReindexOptions
{
Source = "old-index",
Destination = "new-index",
Pipeline = "my-enrich-pipeline",
};
var options = new ServerReindexOptions
{
Source = "old-index",
Destination = "new-index",
RequestsPerSecond = 1000,
Slices = "auto",
};
For advanced use cases not covered by the structured options (scripts, remote reindex, custom conflict handling), pass the complete request body directly. When Body is set, Source, Destination, Query, and Pipeline are ignored:
var options = new ServerReindexOptions
{
Body = """
{
"source": { "index": "old-index" },
"dest": { "index": "new-index" },
"script": { "source": "ctx._source.tag = 'migrated'" }
}
""",
};
| Property | Type | Default | Description |
|---|---|---|---|
Source |
string? |
null |
Source index name. Either this or SourceContext required (unless Body is set). |
Destination |
string? |
null |
Destination index name. Either this or DestinationContext required (unless Body is set). |
SourceContext |
ElasticsearchTypeContext? |
null |
Auto-resolves source from WriteAlias. |
DestinationContext |
ElasticsearchTypeContext? |
null |
Auto-resolves destination from WriteAlias. |
Query |
string? |
null |
JSON query body to filter source documents. |
Pipeline |
string? |
null |
Ingest pipeline name. |
RequestsPerSecond |
float? |
null |
Throttle. Use -1 for unlimited. |
Slices |
string? |
null |
"auto" or a number string. |
PollInterval |
TimeSpan |
5s |
How often to poll the task status. |
Body |
string? |
null |
Full override body JSON. |
Each yielded progress snapshot exposes:
| Property | Type | Description |
|---|---|---|
TaskId |
string |
The Elasticsearch task ID. |
IsCompleted |
bool |
Whether the task has finished. |
Total |
long |
Total documents to process. |
Created |
long |
Documents created. |
Updated |
long |
Documents updated. |
Deleted |
long |
Documents deleted. |
Noops |
long |
Documents that were no-ops. |
VersionConflicts |
long |
Version conflicts encountered. |
Elapsed |
TimeSpan |
Time elapsed since the task started. |
FractionComplete |
double? |
0.0 to 1.0, or null if total is unknown. |
Error |
string? |
Error description if the task failed. |
- Client-side reindex: reindex with application-level document transforms
- Delete by query: uses the same async task polling pattern
- Incremental sync: uses server-side reindex internally