Configuration Keys Reference
The settings you will actually touch — tuning, reproducing a bug, or reading someone's cluster — grouped by area, each with its default, its scope, and the chapter that explains the machinery behind it. Read the chapter before you change a key in a PR; a setting is the public face of a subsystem.
Two scope axes matter, and both are in every table:
| Axis | Values | Means |
|---|---|---|
| Where | cluster / index / node | Set via _cluster/settings, an index's _settings / creation body, or opensearch.yml |
| When | static / dynamic | static requires a restart (node) or index recreation; dynamic can be changed live |
Warning: Defaults drift across versions. The defaults below are representative, not gospel — a minor release can change one. Confirm the real value and scope in your version:
# From a running cluster (defaults included, flat keys): curl -s 'localhost:9200/_cluster/settings?include_defaults=true&flat_settings=true' | python3 -m json.tool curl -s 'localhost:9200/my-index/_settings?include_defaults=true&flat_settings=true&pretty' # From source — find the Setting definition (default + scope live in the Setting.* call): grep -rn "number_of_replicas" server/src/main/java/org/opensearch/cluster/metadata/IndexMetadata.java grep -rn "refresh_interval\|REFRESH_INTERVAL" server/src/main/java/org/opensearch/index/IndexSettings.java # Most setting *keys* are declared in a *Settings class — grep for it: grep -rln "public static final Setting" server/src/main/java/org/opensearch/ | grep Settings
Note: "cluster manager" (formerly "master") is the current term. The bootstrap setting is
cluster.initial_cluster_manager_nodes; the oldcluster.initial_master_nodesis a deprecated alias. Several*master*keys have*cluster_manager*equivalents — grep both.
Jump to: Bootstrap & discovery · Allocation · Index basics · Store · Translog · Refresh · Merge · Search · Circuit breakers · k-NN · Slow logs · Security
Node & cluster bootstrap
How a cluster first forms and which nodes can become cluster manager. Read
../deep-dives/discovery-coordination.md.
| Key | Default | Scope | What it does |
|---|---|---|---|
cluster.name | opensearch | node, static | Nodes only join others with the same cluster name |
node.name | hostname | node, static | Human-readable node id in logs/APIs |
node.roles | all (data, ingest, cluster_manager, …) | node, static | Which roles this node serves; [] = coordinating-only |
cluster.initial_cluster_manager_nodes | (none) | node, static | First boot only: the seed set that forms the initial quorum. Remove after bootstrap. (alias: cluster.initial_master_nodes) |
discovery.seed_hosts | ["127.0.0.1", "[::1]"] | node, static | Addresses to contact to discover the cluster |
discovery.type | zen (multi-node) | node, static | single-node skips bootstrap/quorum for one node |
cluster.publish.timeout | 30s | cluster, dynamic | How long the manager waits for a state to be acked/committed |
Warning: Setting
cluster.initial_cluster_manager_nodeson an already-bootstrapped cluster is a classic mistake — it is honored only on the very first formation. After that it does nothing and should be removed.
Allocation & routing
How shards are placed and rebalanced. Read
../deep-dives/shard-allocation.md.
| Key | Default | Scope | What it does |
|---|---|---|---|
cluster.routing.allocation.enable | all | cluster, dynamic | Gate allocation (all / primaries / new_primaries / none) — set none during maintenance |
cluster.routing.rebalance.enable | all | cluster, dynamic | Gate rebalancing moves |
cluster.routing.allocation.cluster_concurrent_rebalance | 2 | cluster, dynamic | Max concurrent rebalancing relocations cluster-wide |
cluster.routing.allocation.node_concurrent_recoveries | 2 | cluster, dynamic | Max concurrent incoming+outgoing recoveries per node |
cluster.routing.allocation.disk.watermark.low | 85% | cluster, dynamic | Above this, no new shards allocated to the node |
cluster.routing.allocation.disk.watermark.high | 90% | cluster, dynamic | Above this, shards are moved off the node |
cluster.routing.allocation.disk.watermark.flood_stage | 95% | cluster, dynamic | Above this, indices on the node go read-only |
cluster.routing.allocation.awareness.attributes | (none) | cluster, dynamic | Spread replicas across zones/racks by node attribute |
index.routing.allocation.{require,include,exclude}.<attr> | (none) | index, dynamic | Pin/steer an index's shards to nodes by attribute |
index.routing.allocation.total_shards_per_node | -1 (unlimited) | index, dynamic | Cap shards of one index per node |
Index basics
The shape of an index. Read
../deep-dives/index-shard-lifecycle.md
and the sharding masterclass.
| Key | Default | Scope | What it does |
|---|---|---|---|
index.number_of_shards | 1 | index, static | Primary shard count; fixed at creation (change only via split/shrink/reindex) |
index.number_of_replicas | 1 | index, dynamic | Replica copies per primary; safe to change live |
index.number_of_routing_shards | derived | index, static | Target shard count enabling future _split (sets routing hash space) |
index.routing_partition_size | 1 | index, static | With custom routing, spread a routing value across N shards |
index.auto_expand_replicas | false | index, dynamic | Auto-set replicas to a range (e.g. 0-1) as nodes change |
index.hidden | false | index, dynamic | Hide the index from wildcard expansion |
index.blocks.read_only / .write / .read | false | index, dynamic | Per-index access blocks |
Note:
number_of_shardsis the single most consequential static setting. Too many small shards wastes cluster-state and overhead; too few caps parallelism. See the sharding masterclass for the sizing model.
Store
How a shard's files are accessed on disk. Read
../masterclass/storage-engine/lab-03-store-types-mmap.md.
| Key | Default | Scope | What it does |
|---|---|---|---|
index.store.type | hybridfs* | index, static | Directory implementation: fs / niofs / mmapfs / hybridfs (*version-dependent default) |
index.store.preload | [] | index, static | File extensions to warm into the OS page cache on open (e.g. ["nvd","dvd"]) |
node.store.allow_mmap | true | node, static | Allow memory-mapped directories at all (set false where vm.max_map_count can't be raised) |
Warning:
mmapfs/hybridfsneed a highvm.max_map_count(the bootstrap check enforces262144). If you can't raise it, setindex.store.type: niofsornode.store.allow_mmap: false.
Translog
Durability between commits. Read ../deep-dives/translog.md.
| Key | Default | Scope | What it does |
|---|---|---|---|
index.translog.durability | request | index, dynamic | request = fsync the translog on every write request; async = fsync periodically (faster, can lose the last interval on crash) |
index.translog.sync_interval | 5s | index, dynamic | With async, how often to fsync |
index.translog.flush_threshold_size | 512mb | index, dynamic | Translog size that triggers a Lucene flush (commit) to trim it |
Warning:
index.translog.durability: asynctrades durability for indexing throughput — a crash can lose up tosync_intervalof writes. Only choose it when the data source can replay.
Refresh
Search visibility (near-real-time). Read
../deep-dives/refresh-flush-merge.md.
| Key | Default | Scope | What it does |
|---|---|---|---|
index.refresh_interval | 1s | index, dynamic | How often new docs become searchable; -1 disables (bulk-load trick) |
index.max_result_window | 10000 | index, dynamic | Max from + size; beyond it use search_after/PIT |
index.search.idle.after | 30s | index, dynamic | After this with no searches, a shard stops auto-refreshing until queried |
Note: Setting
index.refresh_interval: -1during a large bulk load, then restoring it and forcing one refresh, is the standard ingest-throughput win — at the cost of visibility during the load.
Merge
Background segment consolidation. Read
../lucene/indexwriter-and-merges.md.
| Key | Default | Scope | What it does |
|---|---|---|---|
index.merge.scheduler.max_thread_count | max(1, min(4, procs/2)) | index, dynamic | Concurrent merge threads per shard |
index.merge.policy.max_merged_segment | 5gb | index, dynamic | Cap on a merged segment's size |
index.merge.policy.segments_per_tier | 10 | index, dynamic | Roughly how many segments per size tier before merging |
index.merge.policy.floor_segment | 2mb | index, dynamic | Treat segments below this as this size (avoids many tiny merges) |
Search
Query execution and safety. Read
../deep-dives/search-execution.md and the
concurrent segment search masterclass.
| Key | Default | Scope | What it does |
|---|---|---|---|
search.concurrent_segment_search.mode | auto/all* | cluster + index, dynamic | Enable concurrent segment search (*default-on since 3.0; older toggle was .enabled) |
search.concurrent.max_slice_count | 0 (auto) | cluster + index, dynamic | Max slices (parallel segment groups) per shard; 0 lets the engine choose |
search.max_buckets | 65536 | cluster, dynamic | Hard cap on aggregation buckets per response (memory safety) |
search.default_search_timeout | -1 (none) | cluster, dynamic | Default per-request search timeout |
search.allow_expensive_queries | true | cluster, dynamic | Allow costly queries (scripts, regexp, prefix, joins, wildcard) |
index.max_terms_count | 65536 | index, dynamic | Cap terms in a terms query |
Note:
search.concurrent_segment_search.*setting names have changed across versions (an early.enabledboolean, later a.modeenum). Grepgrep -rn "concurrent_segment_search" server/src/main/java/to see your version's exact keys; the masterclass covers the model.
Circuit breakers
Memory guards that reject before they OOM. Read
../deep-dives/circuit-breakers-memory.md.
| Key | Default | Scope | What it does |
|---|---|---|---|
indices.breaker.total.limit | 95% (with real-memory) | cluster, dynamic | Parent breaker ceiling across all children |
indices.breaker.total.use_real_memory | true | node, static | Account actual heap usage, not just reserved estimates |
indices.breaker.fielddata.limit | 40% | cluster, dynamic | Cap heap for fielddata |
indices.breaker.request.limit | 60% | cluster, dynamic | Cap heap for per-request structures (aggregations via BigArrays) |
network.breaker.inflight_requests.limit | 100% | cluster, dynamic | Cap heap for in-flight request bytes |
k-NN
Vector search settings (the k-NN plugin). Read
../knn/native-jni-and-memory.md and
../knn/architecture.md.
| Key | Default | Scope | What it does |
|---|---|---|---|
index.knn | false | index, static | Enable k-NN (attaches the vector codec) for the index |
index.knn.algo_param.ef_search | 100 | index, dynamic | Default HNSW query-time beam width (efSearch) |
knn.memory.circuit_breaker.limit | 50% | cluster, dynamic | Cap native off-heap memory for k-NN indices (separate from the JVM breakers) |
knn.memory.circuit_breaker.enabled | true | cluster, dynamic | Whether the k-NN native-memory breaker is active |
knn.cache.item.expiry.enabled / .minutes | false / 3h | cluster, dynamic | Evict idle native indices from the off-heap cache |
knn.algo_param.index_thread_qty | 1 | cluster, dynamic | Native HNSW build threads per segment |
Warning: The k-NN native memory breaker (
knn.memory.circuit_breaker.limit) guards off-heap memory used by faiss/nmslib, which is invisible to the JVM circuit breakers. Size it against system RAM, not heap. See../knn/native-jni-and-memory.md.
Slow logs
Per-shard logging of slow operations. Read the debugging masterclass.
| Key | Default | Scope | What it does |
|---|---|---|---|
index.search.slowlog.threshold.query.{warn,info,debug,trace} | -1 (off) | index, dynamic | Log a query phase slower than the threshold at that level |
index.search.slowlog.threshold.fetch.{warn,info,debug,trace} | -1 (off) | index, dynamic | Same for the fetch phase |
index.indexing.slowlog.threshold.index.{warn,info,debug,trace} | -1 (off) | index, dynamic | Log an indexing op slower than the threshold |
index.indexing.slowlog.source | 1000 | index, dynamic | Chars of _source to log (false/0 to omit) |
# Turn on a 200ms query slow log on one index, then watch the per-shard log:
curl -s -XPUT 'localhost:9200/my-index/_settings' -H 'Content-Type: application/json' -d'
{ "index.search.slowlog.threshold.query.warn": "200ms" }'
# logs land in <logs>/<cluster>_index_search_slowlog.json
Security
The bundled security plugin's TLS and transport settings (opensearch.yml). Read
the security masterclass.
| Key | Default | Scope | What it does |
|---|---|---|---|
plugins.security.ssl.transport.enabled | true (when security on) | node, static | TLS on the node↔node transport (9300) — mandatory when security is enabled |
plugins.security.ssl.transport.pemcert_filepath / .pemkey_filepath / .pemtrustedcas_filepath | (none) | node, static | Node cert / key / trusted CAs for transport TLS |
plugins.security.ssl.http.enabled | false | node, static | TLS on the REST/HTTP layer (9200) |
plugins.security.ssl.http.pemcert_filepath / .pemkey_filepath / .pemtrustedcas_filepath | (none) | node, static | Cert / key / trusted CAs for HTTP TLS |
plugins.security.authcz.admin_dn | (none) | node, static | The admin certificate DN(s) allowed to run securityadmin.sh |
plugins.security.nodes_dn | (none) | node, static | DNs allowed to join as cluster nodes (transport authn) |
plugins.security.allow_default_init_securityindex | false | node, static | Auto-initialize the security config index from demo files |
plugins.security.disabled | false | node, static | Turn the security plugin off entirely (dev only) |
Warning: When security is enabled, transport TLS is not optional — the plugin refuses to start nodes without it. The HTTP layer can run plaintext for local dev, but never in production. See
../masterclass/security/lab-01-authn-tls.md.
Reading effective settings end to end
Two commands turn "what is actually set?" into a definitive answer:
# Every cluster setting, defaults included, as flat keys you can grep:
curl -s 'localhost:9200/_cluster/settings?include_defaults=true&flat_settings=true' \
| python3 -m json.tool | grep -i 'watermark\|breaker\|concurrent'
# One index's effective settings (persistent + transient + defaults):
curl -s 'localhost:9200/my-index/_settings?include_defaults=true&flat_settings=true&pretty'
To change a dynamic cluster setting live (persistent survives restart, transient does not):
curl -s -XPUT 'localhost:9200/_cluster/settings' -H 'Content-Type: application/json' -d'
{ "persistent": { "cluster.routing.allocation.enable": "primaries" } }'
Note: A setting the API rejects as "unknown" usually means it is registered by a plugin that isn't installed, was renamed, or is
static(and so cannot be set via_cluster/settingsat all). Confirm by grepping the owning*Settingsclass — theSetting.*Setting(...)call shows the exact key, default, scope, andProperty.Dynamic/Property.NodeScopeflags.