Reindexing into a new generation
This guide shows you how to roll out an index definition change by having the engine reindex existing documents into a new generation.
Use this engine-driven procedure when your documents are already indexed and the source generation retains document copies (source mode set to a value other than none). The engine copies documents and replays changes internally without requiring you to stream documents back to Exofind. If your source index does not keep stored sources, or if you want to stream documents from an external system yourself, use the manual procedure in Rolling out a definition change. For conceptual background, see Generations.
Prerequisites
Section titled “Prerequisites”Before you begin, verify the following:
- Your API key has the
indexes.reindexpermission (included in theadminrole) and permissions forproducts@*. Checking job status requiresindexes.read. Automatic promotion also requiresindexes.promote, and creating the target generation in the same request requiresindexes.write. - The source generation has a primary key and keeps document sources (
sourcemode is notnone). - The new generation definition uses the same primary key field name and type as the source generation.
Starting the reindex job
Section titled “Starting the reindex job”You can create the target generation and start the reindex job in one request by using the ?reindex= query parameter, or you can create the generation first and start the job in a separate step.
Choose a promotion strategy:
auto(default): The engine streams documents, replays incoming writes, and promotes the new generation as soon as it catches up.manual: The engine fills the generation and pauses in thereadyphase while keeping it up to date. You can compare search results before manually promoting.
Option A: Create and start in one request
Section titled “Option A: Create and start in one request”To create products@2 and immediately start reindexing from the live generation, add ?reindex=auto or ?reindex=manual to your PUT request:
PUT /v1alpha1/admin/indexes/products@2?reindex=manualContent-Type: application/json
{ "fields": { "id": { "type": "string", "primaryKey": true, "required": true }, "title": { "type": "string", "matching": { "typoTolerance": {} } }, "brand": { "type": "string", "filter": {}, "facet": {} } }}Option B: Create the generation and start the job separately
Section titled “Option B: Create the generation and start the job separately”-
Create the empty generation:
PUT /v1alpha1/admin/indexes/products@2Content-Type: application/json{"fields": {"id": { "type": "string", "primaryKey": true, "required": true },"title": { "type": "string", "matching": { "typoTolerance": {} } },"brand": { "type": "string", "filter": {}, "facet": {} }}} -
Start the reindex job on the empty generation:
POST /v1alpha1/admin/indexes/products@2/actions/reindexContent-Type: application/json{"from": "products@1","promote": "manual"}The endpoint returns
202 Acceptedwith the initial job record. TheLocationheader names the status endpoint of the job. If you omit the request body, the job defaults to reading from the live generation withpromote: "auto".
Tracking reindex progress
Section titled “Tracking reindex progress”-
Check the status of the reindex job:
GET /v1alpha1/admin/reindexes/productsThe response displays the current phase and progress counts:
{"id": "6f1c2a9d8b3e4c05","index": "products","target": "products@2","source": "products@1","phase": "copying","promote": "manual","documentsCopied": 125000,"sourceDocuments": 2400000,"backlog": 4100,"error": null,"startedBy": "3f9a1c7e2b8d4650","node": "node-a-7f21","startedAt": "2026-08-28T10:15:30Z","updatedAt": "2026-08-28T10:16:02Z","finishedAt": null}idtells this job from one that replaces it on the same index.nodenames the node running the job, andstartedBythe key that started it. -
Monitor the
phasefield as the job progresses through its lifecycle:Phase Meaning pendingAccepted and waiting for an available concurrency slot on the node. copyingStreaming documents from the source generation in primary key order. replayingApplying documents modified in the source while the initial copy ran. readyCaught up and waiting for promotion ( manualmode only). The job runs periodic catch-up sweeps.promotingPausing incoming writes briefly for the final catch-up sweep and promotion. doneSuccessfully promoted and active. failedHalted due to an error before promotion occurred. cancelledStopped by a cancellation request.
To view every reindex job across your deployment, send a GET request to /v1alpha1/admin/reindexes.
Comparing results and promoting (manual mode)
Section titled “Comparing results and promoting (manual mode)”If you started the job with promote: "manual", complete the following steps once the job reaches the ready phase:
-
Search both the target generation and the live index to compare query results:
POST /v1alpha1/indexes/products@2/searchPOST /v1alpha1/indexes/products/search -
Promote the target generation when you are ready to make it live:
POST /v1alpha1/admin/indexes/products@2/actions/promoteThe promote endpoint drains any remaining change backlog, executes the promotion, and transitions the job to
done. If you attempt to promote before the job reachesready, the request returns409 Conflictwith error codereindex:target_busy.If another generation was promoted while the job ran, the request returns
409 Conflictwith error codeindex:generation:live_moved, and the job moves to thefailedphase. The target holds only what the job read from its source, and none of the writes made to the generation promoted in between. Start a new reindex job that reads from the generation the index now serves from.
Confirming the rollout
Section titled “Confirming the rollout”To confirm that the new generation is serving live traffic, search the index by name:
POST /v1alpha1/indexes/products/searchThe node that processed the promotion answers immediately from products@2. Other nodes answer from products@2 within EXOFIND_INDEXES_REFRESH_INTERVAL.
Cancelling a job
Section titled “Cancelling a job”To cancel an active reindex job:
-
Send a cancellation request:
POST /v1alpha1/admin/reindexes/products/actions/cancel -
Delete the target generation to clean up partially copied data:
DELETE /v1alpha1/admin/indexes/products@2
Handling a failed job
Section titled “Handling a failed job”If a document violates the target schema (for example, missing a required field or containing an incompatible type), the job halts in the failed phase before any promotion takes place:
-
Check the job status to identify the failure cause and document key:
GET /v1alpha1/admin/reindexes/productsInspect the
errorfield in the response:{"index": "products","target": "products@2","source": "products@1","phase": "failed","error": "The target refused the document with key `prod_12345`: Required field `sku` is missing","updatedAt": "2026-08-28T10:18:12Z","finishedAt": "2026-08-28T10:18:12Z"} -
Delete the failed target generation:
DELETE /v1alpha1/admin/indexes/products@2 -
Fix the definition or correct the document data in the live generation before starting a new reindex job.
Deleting the previous generation
Section titled “Deleting the previous generation”After confirming that the new generation works as expected, delete the old generation:
DELETE /v1alpha1/admin/indexes/products@1Note: You cannot delete the generation that an index currently answers from. Unremoved generations continue to consume storage and local disk space.
Related
Section titled “Related”- Rolling out a definition change - The rollout the reindex job fills a generation for.
- Surviving Lucene upgrades - Reindexing an index before it becomes unreadable.
- Admin API - The generation and reindex job endpoints.
- Generations - Why an index is a name with generations under it.
- Operating a deployment - Watching disk while two generations are held.
- Reading documents back - Refilling from a source outside the engine instead.
Exofind is built by Level Four AB and is available under the Apache License 2.0.