With over 10 years of experience and 500+ successful Elasticsearch migrations, we guarantee zero-downtime reindexing for your production clusters. Our certified experts have handled indices up to 500 million documents without a single incident.
You changed a field mapping in production — and got an error. Elasticsearch does not allow renaming fields, changing types, or adding analyzers to an existing index. The only solution is reindexing, but it blocks writes: you would have to stop the application, losing data during migration. We solve this via the blue/green strategy with aliases. The application runs without downtime, and reindexing happens in the background. An alias is an abstraction: the application writes and reads through the alias, never knowing the physical index name. The old index remains accessible while the new one is filled. Then the alias is switched atomically — and that's it.
How to achieve zero-downtime Elasticsearch reindexing?
Compare two strategies:
| Parameter | Blue/Green with alias | Direct reindex |
|---|---|---|
| Write availability | Yes (via alias) | No (index locked) |
| Downtime | 0 | Reindex + verification time |
| Rollback capability | Instant (switch alias back) | No |
| Implementation complexity | Medium (2–3 days) | Low (1 day) |
| Conflict control | Incremental sync | Impossible |
Blue/Green with alias is 5x faster and saves thousands of dollars in potential downtime costs.
How the Blue/Green strategy works
An alias acts as a pointer to an index. According to the official Elasticsearch documentation, aliases allow abstracting the physical index. The application works with alias products, unaware of the physical name.
Step 1 — create a new index with the desired mapping:
PUT /products_v2 { "settings": { "number_of_shards": 3, "number_of_replicas": 0, "refresh_interval": "-1", "analysis": { "analyzer": { "product_analyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "russian_stemmer"] } } } }, "mappings": { "properties": { "id": { "type": "keyword" }, "title": { "type": "text", "analyzer": "product_analyzer", "fields": { "keyword": { "type": "keyword" } } }, "price": { "type": "scaled_float", "scaling_factor": 100 }, "new_field": { "type": "keyword" } } } } During loading, disable replicas and refresh — this speeds up writes by up to 80%.
Launch reindex with parallel slices
Start reindex with slices: auto:
POST _reindex?wait_for_completion=false { "source": { "index": "products_v1", "size": 500 }, "dest": { "index": "products_v2", "op_type": "create" }, "conflicts": "proceed", "slices": "auto" } slices: auto splits the task into as many slices as the source index has shards. Each slice runs independently — achieving 5–10x speedup over sequential execution.
Incremental synchronization
While reindexing runs, the application continues to write to the old index. To catch up new data, perform an incremental sync:
POST _reindex?wait_for_completion=false { "source": { "index": "products_v1", "query": { "range": { "updated_at": { "gte": "now-1h", "lte": "now" } } } }, "dest": { "index": "products_v2", "op_type": "index", "version_type": "external" } } version_type: external uses _version to resolve conflicts. This requires an updated_at field in the mapping.
How to ensure atomic switching?
After reindexing and synchronization complete, run:
# 1. Restore production settings on the new index PUT /products_v2/_settings { "index.number_of_replicas": 1, "index.refresh_interval": "1s" } # 2. Wait for replica recovery curl -u elastic:pw "localhost:9200/_cluster/health/products_v2?wait_for_status=green&timeout=30s" # 3. Atomically switch the alias POST _aliases { "actions": [ { "add": { "index": "products_v2", "alias": "products", "is_write_index": true } }, { "remove": { "index": "products_v1", "alias": "products" } } ] } The operation is atomic — no requests are lost. Rollback plan: reverse the alias switch. Do not delete the old index for 24–48 hours. If the new mapping turns out incorrect, simply switch the alias back. All data in the old index remains intact. Optionally, keep a backup of both indices.
Why parallel slices speed up the process dramatically?
Without slices, reindex runs in a single thread. With slices: auto, the task splits into N sub-tasks (by number of source shards). On an index with 5 shards and 100 million documents, reindex takes 6 hours without slices and about 1 hour with them — a 5–6x speedup. Cluster load is balanced evenly.
Data transformation via Painless
If you need to alter the document structure (split fields, normalize prices), use a script in _reindex:
POST _reindex { "source": { "index": "products_v1" }, "dest": { "index": "products_v2" }, "script": { "source": """ if (ctx._source.full_name != null) { def parts = ctx._source.full_name.splitOnToken(' '); ctx._source.first_name = parts[0]; ctx._source.last_name = parts.length > 1 ? parts[1] : ''; ctx._source.remove('full_name'); } if (ctx._source.price instanceof String) { ctx._source.price = Float.parseFloat(ctx._source.price.replace(',', '.')); } """, "lang": "painless" } } Step-by-step zero-downtime reindexing
- Create a new index with optimized settings (disable replicas and refresh, configure analyzers).
- Start reindex with
slices: auto— speeds up the process up to 10x. - Perform incremental synchronization to catch up new data.
- Restore production settings (replicas, refresh_interval).
- Wait for the cluster to reach green status.
- Atomically switch the alias — reindexing is complete.
Reindexing stages with aliases
| Stage | Action | Approximate time |
|---|---|---|
| 1. Preparation | Audit current mapping, design new one | 1 day |
| 2. Index creation | Create new index with settings | 10 minutes |
| 3. Data loading | Reindex with slices: auto | 1–6 hours (depends on volume) |
| 4. Synchronization | Incremental sync | 10–30 minutes |
| 5. Switch | Atomic alias switch | 1 second |
| 6. Monitoring | Observe for 48 hours post-migration | 2 days |
What's included
- Audit of current mapping and data — identify fields needing changes, analyze volumes and access patterns.
- Design of new mapping — considering analyzers, nested fields, and data types.
- Migration script development — configure parallel slices, incremental sync, transformation scripts.
- Execution and monitoring — track progress, speed, errors.
- Process documentation — describe steps for future reuse.
- Post-migration support — 48 hours of monitoring after switching.
Contact us to develop a migration plan. Get a consultation for your scenario without downtime.







