How does OpenSearch shard and replicate an index across nodes, and why can't you change the primary shard count after an index is created?
Quick Answer
An OpenSearch index is split into a fixed number of primary shards at creation time, each an independent Lucene index holding a portion of the data, determined by hashing each document's routing value against that exact shard count. Every primary can have one or more replica shards, which are exact copies used for redundancy and read scaling. The primary count is locked in at creation because the routing formula depends on that exact number — changing it later would misroute every existing document, so 'resizing' primary count means reindexing into a brand-new index instead.
Detailed Answer
Imagine a large apartment complex's management company decides upfront to divide all tenant mail into exactly ten mailroom bins, using a formula like the last digit of the apartment number. Every mail carrier and every tenant relies on that formula to know which bin holds which mail. If the company suddenly switched to seven bins instead of ten, the old formula's results become meaningless — mail correctly sorted into bin six under the ten-bin formula might belong somewhere completely different under the seven-bin formula, so every single piece of mail in the building would have to be physically re-sorted to make the new bin count correct.
OpenSearch indices work the same way. When you create an index, you specify number_of_shards, the primary shard count, defaulting to one in modern versions but historically five, and every document written to that index is deterministically routed to one specific primary shard using a hash of its _id, or a custom routing value, modulo the shard count. This fixed, pre-committed shard count exists because that routing formula must stay constant for OpenSearch to reliably find a document later — if the shard count could silently change, the same formula applied to the same document would compute a different shard, breaking lookups for anything indexed before the change took effect.
Internally, each primary shard is a fully independent Lucene index, Lucene being the underlying single-node search library OpenSearch is built on, with its own inverted index, segments, and merge policy. Replica shards are exact copies of a primary, kept in sync as new documents are written — the primary indexes first, then replicates the operation to its replicas — and OpenSearch can route read and search requests to either a primary or any of its replicas to spread query load, while writes always go through the primary first. The cluster manager tracks which node holds which shard copy and handles reassignment if a node holding a shard goes down unexpectedly.
In production, choosing the primary shard count upfront matters enormously: too few shards for a large, growing dataset, like a year of payments-api-logs, means each shard grows huge and becomes slow to search and rebalance; too many small shards across a cluster wastes memory on per-shard overhead, since each shard consumes file handles and heap for its own Lucene structures, and can itself become a cluster stability problem at scale. Teams commonly use rollover-based index patterns, creating a new index every day or week and aliasing them together, specifically to sidestep the 'I picked the wrong shard count forever' problem, since they're setting the shard count for one time-bounded chunk of data rather than for all data forever.
The gotcha: engineers coming from relational databases often assume you can just add more shards the way you'd add more database partitions dynamically, but OpenSearch has no live operation for primary shards at all — the only path is the _reindex, _split, or _shrink APIs, which physically copy or reorganize data into a brand-new index with a different shard count. That means correcting a sizing mistake after the fact requires enough temporary disk and cluster capacity to hold both the old and new index simultaneously during the migration, which is often the real operational blocker rather than the reindex logic itself being complicated.