← Knowledge hub
Tutorialby Uptime Room· September 24, 2026· 6 min read

Elasticsearch Health Check: Green, Yellow, Red

An elasticsearch health check returns green, yellow or red, and yellow is where the false alarms live. Here is what to check and what to assert.

An elasticsearch health check answers with a colour, and the middle colour is where most false alarms come from. Green means every shard is allocated. Red means at least one primary shard is missing and some of your data cannot be searched. Yellow means something in between, and whether it is an emergency depends entirely on how the cluster is built.

What the cluster health API returns

One GET request gives you the whole picture. The cluster health operation returns a small JSON document with the status colour, the node count, the shard counts and the size of the pending task queue.

curl -s -u elastic:$ES_PASSWORD \
  "https://localhost:9200/_cluster/health?pretty"
{
  "cluster_name": "search-prod",
  "status": "yellow",
  "number_of_nodes": 3,
  "number_of_data_nodes": 3,
  "active_primary_shards": 42,
  "active_shards": 79,
  "relocating_shards": 0,
  "initializing_shards": 2,
  "unassigned_shards": 3,
  "number_of_pending_tasks": 0
}

Read unassigned_shards alongside the colour. Three unassigned shards with a yellow status means replicas are missing, which costs you redundancy but not data. The same number with a red status means primaries are missing, and queries against those indices are returning incomplete results right now.

For a quick look by eye, GET /_cat/health?v prints the same fields as one aligned row. It is the answer people still reach for, and it has been the accepted answer on Stack Overflow since 2014.

ColourPrimariesReplicasWhat to do
GreenAll allocatedAll allocatedNothing
YellowAll allocatedAt least one missingInvestigate today, do not page
RedAt least one missingIrrelevantPage immediately

Why is a single-node cluster always yellow?

Because a replica shard is never allocated on the same node as its primary. Elasticsearch creates indices with one replica by default, and a single-node cluster has nowhere to put it. The cluster is working perfectly and will report yellow forever.

This is the single most common false alarm in an elasticsearch health check, and it hits development and CI environments hardest. Two fixes exist. In a development cluster, set number_of_replicas to zero on the index template so the expected state is genuinely green. In production, alert on red and treat yellow as a ticket.

curl -s -u elastic:$ES_PASSWORD -X PUT \
  "https://localhost:9200/my-index/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"index": {"number_of_replicas": 0}}'

We tested a three-node staging cluster that sat yellow for eleven days after a node replacement. Nobody noticed, because the dashboard had been yellow so often that the colour had stopped meaning anything. That is the real cost of alerting on the wrong colour.

Gating a startup on the cluster being ready

The health endpoint can block until the cluster reaches a given status. That is exactly what a container healthcheck or an entrypoint script needs. Pass wait_for_status and a timeout, and the request holds until the condition is met or the clock runs out.

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS 'http://localhost:9200/_cluster/health?wait_for_status=yellow&timeout=5s'"]
      interval: 10s
      timeout: 10s
      retries: 12
      start_period: 60s

Use wait_for_status=yellow in a single-node container and green in a real cluster. Waiting for green on a one-node setup produces a container that never becomes healthy, which is the most common failure in this configuration.

The start_period matters more than the retry count. A cluster recovering a large translog can take minutes before it answers at all, and a short start period turns a slow boot into a restart loop.

Turning an elasticsearch health check into a monitor

A container healthcheck dies with the host that runs it. To know the cluster is reachable and healthy from somewhere else, point an api monitor at the same endpoint. Pass wait_for_status so the cluster grades itself, because a cluster below that status answers 408 instead of 200.

curl -X POST https://uptimeroom.com/api/v1/monitors \
  -H "Authorization: Bearer urm_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "search cluster health",
    "type": "api",
    "target": "https://es.example.com:9200/_cluster/health?wait_for_status=yellow&timeout=5s",
    "method": "GET",
    "intervalSec": 60,
    "regions": ["london", "singapore"],
    "headers": {"Authorization": "ApiKey REDACTED"},
    "expectedStatus": [200],
    "timeoutMs": 10000
  }'

That query parameter is what makes the status code worth checking. A red cluster fails the request and a yellow one passes, which is exactly the paging rule set out above.

Node count needs a second check. A cluster that loses a node stays green while the survivors hold every shard, so the colour will not tell you that redundancy just halved. Add a keyword monitor matching "number_of_nodes":3 if that should reach somebody. Monitor fields are documented in the REST API reference, and the same pattern applies to any JSON endpoint, as covered in API monitoring.

Two practical notes on access. Security is enabled by default on modern clusters, so the request needs an API key with the monitor cluster privilege rather than a superuser credential. The endpoint is usually bound to a private network. Either check an authenticated proxy path, or expose a narrow read-only route and allowlist the addresses on the probe IPs page.

Reading the numbers behind the colour

Three fields in the response are worth watching independently of the status. initializing_shards above zero for more than a few minutes means recovery is stuck rather than progressing. relocating_shards staying high means the balancer is thrashing, usually after a disk watermark pushed shards off a node.

number_of_pending_tasks is the one that predicts trouble. It is the master node's queue, and a queue that keeps growing means cluster-state updates are backing up. That shows as slow index creation and slow mapping updates long before it shows as a colour change.

None of those three produce a colour, which is why a check that reads only the status misses the interesting half of the document. Assert on the colour for outages and graph the counters for capacity.

What the colour does not tell you

Green is a statement about shard allocation and nothing else. A green cluster can reject writes after a disk watermark is crossed. It can serve queries eight times slower than yesterday. It can return empty result sets because an ingest pipeline broke upstream.

The health report endpoint goes further, returning named indicators with a diagnosis attached rather than one colour. It is worth polling alongside the simple status when you want a reason rather than a symptom.

For the query path itself, assert on an actual search response. Run a known query and check that a known document comes back. That is the difference between "the cluster is up" and "search works", the same reasoning behind keyword monitoring.

Common mistakes

Paging on yellow. Yellow means reduced redundancy, not lost data. Send it to a ticket queue and reserve the pager for red.

Checking only the plain HTTP status code. The health endpoint returns 200 while reporting red, because the request succeeded. Pass wait_for_status or match on the body.

Reusing a superuser credential. A monitoring credential that can delete indices is a liability. Scope it to the monitor privilege and rotate it.

Trusting a local check alone. A healthcheck running beside the node cannot see DNS failures, an expired certificate on the proxy, or a security group change. Those need a probe that starts outside the cluster.

A good elasticsearch health check is two checks, not one. Keep the local wait_for_status gate for startup ordering, then add an external check on the status colour and the node count so a silent loss of redundancy still reaches somebody. Both fit inside the free plan, which includes 10 monitors at a 1-minute check interval as of September 2026.

FAQ

What is the Elasticsearch health check endpoint?

It is GET /_cluster/health, which returns a JSON document with the status colour, node counts, shard counts and the pending task queue. For a human-readable single row use GET /_cat/health?v instead. A newer endpoint, /_health_report, returns named indicators with a diagnosis rather than a single colour.

Why is my Elasticsearch cluster status yellow?

Yellow means every primary shard is allocated but at least one replica is not. On a single-node cluster that is permanent, because a replica is never placed on the same node as its primary and indices default to one replica. Set number_of_replicas to zero in development, or alert only on red in production.

How do I check Elasticsearch health with curl?

Run curl against /_cluster/health with credentials, since security is enabled by default on modern clusters. Add the pretty parameter for readable output. To block until the cluster is ready, add wait_for_status with a value of yellow or green plus a timeout, which is what container healthchecks and entrypoint scripts use.

How do I check the health of an API endpoint like this one?

Assert on the response body, not just the status code. The health endpoint returns 200 even while reporting red, because the HTTP request itself succeeded. Check that the status field is not red and that the node count matches what you expect, since a cluster can stay green after losing a node.

Does a green status mean Elasticsearch is working?

No. Green is a statement about shard allocation only. A green cluster can still be rejecting writes after crossing a disk watermark, answering queries far slower than usual, or returning empty results because an upstream ingest pipeline broke. Run a known query and assert on a known document if you need to prove search works.

Related reading