# prometheus-community/elasticsearch_exporter: polling an Elasticsearch cluster on every scrape

> A Go binary that exposes Elasticsearch and OpenSearch cluster numbers in Prometheus text format, fetching fresh values from the cluster on each scrape instead of caching. Worth reading for its flag provenance table and its scrape load warning; plan your interval before you enable the heavy collectors.

**prometheus-community/elasticsearch_exporter** — Elasticsearch stats exporter for Prometheus

- Repository: https://github.com/prometheus-community/elasticsearch_exporter
- Stars: 2,092 · Forks: 831
- Language: Go
- License: Apache-2.0
- Published: 2026-10-13 · Updated: 2026-10-13 · Language: en
- Canonical page: https://hysenlabs.com/projects/prometheus-community-elasticsearch-exporter

## One Go binary queries the cluster on every Prometheus scrape

Prometheus needs an HTTP endpoint that answers with text exposition format, and elasticsearch_exporter is that endpoint for Elasticsearch and OpenSearch. It is an external Go process, not an agent installed inside the cluster: main.go and probe.go sit at the repository root beside the collector/, cluster/, config/ and pkg/ packages, and nothing is deployed onto the cluster nodes themselves.

Values are fetched per scrape rather than held in a cache. That choice keeps the process light on memory and stateless between requests, and it also means the cluster absorbs work in proportion to how often Prometheus asks. The serving side comes from github.com/prometheus/client_golang v1.24.1 and the toolkit github.com/prometheus/exporter-toolkit v0.19.0, arguments are parsed by github.com/alecthomas/kingpin/v2 v2.4.0, and the module declares go 1.26.0. Cluster-facing options use dotted names rather than Go-style dashes, so job configuration reads es.indices and es.all, not a hyphenated form of the same words.

## The Dockerfile exposes 7979 while every run command publishes 9114

The repository's own Dockerfile and the documented run commands disagree about the port. These lines come straight from that file:

```
ARG ARCH="amd64"
ARG OS="linux"
FROM quay.io/prometheus/busybox-${OS}-${ARCH}:glibc
COPY .build/${OS}-${ARCH}/elasticsearch_exporter /bin/elasticsearch_exporter
EXPOSE      7979
USER        nobody
ENTRYPOINT  [ "/bin/elasticsearch_exporter" ]
```

The EXPOSE line names 7979. Every container command given for this exporter maps 9114 to 9114, and the compose sample publishes 127.0.0.1:9114:9114. EXPOSE is image metadata and binds nothing by itself, so the practical risk is a reader who trusts the file and publishes a port that never receives traffic. No explanation for the two numbers appears in the README or anywhere else in the repository, so take 9114 from the run commands and verify the bind address on your first start.

## Scrape interval is the load knob on the master nodes

The exporter fetches information from an Elasticsearch cluster on every scrape, and a scrape interval that is too short can impose load on ES master nodes, particularly when you run with es.all and es.indices enabled.

Sizing that interval means measuring how long fetching /_nodes/stats and /_all/_stats takes on your own cluster. As a last resort, the exporter can be given a dedicated Prometheus job with its own scraping interval, which is a scheduling answer rather than a caching one: nothing in the repository documents a cache, a local store, or a push mode, and no such mechanism shows up in the directory layout.

Cost compounds as collectors stack up. Shard-level figures are heavier than aggregate figures because es.shards also sets es.indices=true and pulls per-shard data into the same request, and the settings, mappings and ilm collectors each add work on top of the base call.

## Collector flags default to false except informational aliases

Most collectors are opt-in. es.uri, es.all, es.indices, es.indices_settings, es.indices_mappings, es.shards, es.ilm and collector.clustersettings all default to false. es.aliases is the one exception and defaults to true, so alias metrics arrive unless you switch them off, which catches out people who expect an exporter to stay silent until configured.

es.shards carries its own catch: the table notes that it also sets es.indices=true, so passing it alone changes the request shape without you naming the second flag. collector.clustersettings replaced the older name es.cluster_settings in v1.6.0, and that rename is recorded in the same table, which leaves any command line assembled for an earlier line of the project carrying a flag name that no longer exists.

Provenance is unusually explicit. One column records where each flag arrived, from 1.0.2 for es.uri, es.all and es.indices, through 1.0.3rc1 for es.shards, 1.0.4rc1 for es.indices_settings and es.aliases, 1.2.0 for es.indices_mappings, and 1.6.0 for es.ilm and collector.clustersettings.

## An empty es.uri turns the exporter into a probe endpoint

One binary covers two operating modes, and the choice is made by the es.uri value.

Single-target mode fills es.uri with the cluster address. The documented form is `<proto>://<user>:<password>@<host>:<port>`, with http://admin:pass@localhost:9200 given as the example, and special characters in the credentials required to be URL-encoded. This mode is what the compose sample uses through the --es.uri=http://elasticsearch:9200 command line.

The default for es.uri is the empty string, and the empty string means something different: leave it empty and the exporter runs only as a multi-target /probe endpoint, with the target supplied by Prometheus at request time. For anyone running several clusters, that is the real alternative to giving every cluster its own container, its own port and its own service entry, and it explains why probe.go and probe_test.go sit at the repository root rather than inside collector/. The trade is that collector tuning moves out of the process and into each scrape configuration.

## Four install paths: quay.io, GHCR, Helm chart, or a source build

Images are published to two registries and both documented tags are :latest, so neither example is reproducible until you edit the tag yourself. Start with the quay.io image and you should see port 9114 on the host:

```bash
docker pull quay.io/prometheuscommunity/elasticsearch-exporter:latest
docker run --rm -p 9114:9114 quay.io/prometheuscommunity/elasticsearch-exporter:latest
```

The same binary is mirrored on GHCR, and the command shape does not change:

```bash
docker pull ghcr.io/prometheus-community/elasticsearch-exporter:latest
docker run --rm -p 9114:9114 ghcr.io/prometheus-community/elasticsearch-exporter:latest
```

For a compose stack the sample keeps the exporter off the public interface by binding the published port to 127.0.0.1 and reaches the cluster over the compose network:

```yaml
elasticsearch_exporter:
    image: quay.io/prometheuscommunity/elasticsearch-exporter:latest
    command:
     - '--es.uri=http://elasticsearch:9200'
    restart: always
    ports:
    - "127.0.0.1:9114:9114"
```

On Kubernetes a chart lives in the community charts repository, installed under a name of your choosing:

```bash
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install [RELEASE_NAME] prometheus-community/prometheus-elasticsearch-exporter
```

Pre-built binaries are published on the project's download page for people who would rather not run a container. Whichever path you take, the same binary answers elasticsearch_exporter --help with the flag summary that every job configuration depends on.

## Collectors, fixtures, mixin dashboards and examples sit in separate directories

The top-level layout tells you where to look before reading code. cluster/ holds the client side, collector/ the per-metric code, config/ the configuration handling and pkg/ the shared helpers. fixtures/ holds test data, and probe.go with probe_test.go covers the probe path.

examples/ is worth the detour: auth_modules.yml, example-prometheus.yml, and kubernetes/ and prometheus/ subdirectories. A sample Prometheus setup exists in the tree even though the documentation never prints it, so a job definition can be copied from examples/example-prometheus.yml rather than assembled from scratch. elasticsearch-mixin/ is not exporter code at all but a Grafana mixin of dashboards and alerts built on these metrics, which saves writing panels for a first pass.

Build and packaging plumbing is visible too: Makefile and Makefile.common with DOCKER_ARCHS set to amd64, armv7, arm64 and ppc64le, a .promu.yml, a .golangci.yml, a .yamllint, and VERSION, MAINTAINERS.md and SECURITY.md at the root. metrics.md is where the metric names the collectors expose are written down, the file to consult before building a recording rule.

## Older clusters and both products at once are the real boundary

Compatibility is bounded by a policy the project spells out: all currently supported versions of Elasticsearch and OpenSearch are in scope, previous versions get reasonable attempts rather than a guarantee, and code maintainability with currently supported versions takes priority. The same paragraph warns that where the two products diverge, some collectors may be compatible with only one of them. For a team on an older cluster, or running Elasticsearch and OpenSearch side by side and expecting one identical set of metrics from both, that is the boundary to check before wiring dashboards.

Rollback is not addressed anywhere in the documentation, and the renamed collector.clustersettings flag carries no upgrade note beyond the table row recording it. Per-scrape cost is the other boundary: a cluster that cannot absorb /_all/_stats on your chosen interval needs its own Prometheus job with a separate interval rather than a faster exporter.

On licensing, the repository ships LICENSE and NOTICE files and the code is published under Apache-2.0, so anyone forking or redistributing the binary keeps those notice files attached to the distribution. The last push on the repository was on 2026-10-01.

## Conclusion

Adopt this exporter when you run one or a handful of Elasticsearch or OpenSearch clusters, want cluster numbers in a known Go process, and already scrape HTTP endpoints with Prometheus. Look elsewhere if you need long retention of cluster history, because the values exist only in each scrape response, or if per-scrape load on master nodes is unacceptable. Before deploying, time /_nodes/stats and /_all/_stats against your own cluster, decide whether es.all and es.indices belong in the job, and confirm the container binds 9114 rather than trusting the Dockerfile's 7979 line.

## FAQ

### What port does the prometheus-community elasticsearch_exporter listen on?

The documented commands publish 9114 to the host, for example docker run --rm -p 9114:9114 quay.io/prometheuscommunity/elasticsearch-exporter:latest. The repository Dockerfile carries a separate EXPOSE 7979 line, and the documentation gives no explanation for the difference, so confirm the bind address on the first start.

### Does elasticsearch_exporter cache cluster values between scrapes?

No. The exporter fetches information from the cluster on every scrape, which is why the documentation warns that a short scrape interval can impose load on ES master nodes, particularly with es.all and es.indices enabled. Nothing in the repository describes a cache or a push mode.

### How do I monitor several Elasticsearch clusters with one exporter?

Leave es.uri empty, its default, and run the exporter only as a multi-target /probe endpoint where Prometheus supplies the target per request. Setting es.uri instead puts it in single-target mode, for example http://admin:pass@localhost:9200, with special characters in the credentials URL-encoded.

### Where do I find the binary and the full list of flags?

Pre-built binaries are published on the project's releases page, and images on quay.io and GHCR. The complete flag summary comes from elasticsearch_exporter --help, and each collector name in that summary carries the version that introduced it.

### Does the exporter support OpenSearch as well as Elasticsearch?

Yes, the project covers metrics for both. It states that all currently supported versions of both are supported, and that where the two diverge it makes reasonable attempts to keep compatibility, with some collectors compatible with only one of them.

## Sources

- [Issues](https://github.com/prometheus-community/elasticsearch_exporter/issues)
- [License: Apache-2.0](https://github.com/prometheus-community/elasticsearch_exporter/blob/master/LICENSE)
- [prometheus-community/elasticsearch_exporter on GitHub](https://github.com/prometheus-community/elasticsearch_exporter)
- [README](https://github.com/prometheus-community/elasticsearch_exporter/blob/master/README.md)
- [Releases](https://github.com/prometheus-community/elasticsearch_exporter/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/prometheus-community-elasticsearch-exporter
