elasticsearch-js

The official Node.js client for Elasticsearch, giving JavaScript and TypeScript apps a typed, fully-featured way to talk to an Elasticsearch cluster.

SDK
npm
v9.5.1
5,290 stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
93 /100 Excellent
Development Activity 88
Maintenance 92
Community 92
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
82 /100 Excellent
Architecture 88
Code Quality 90
Innovation 78
Learning Curve 70

@elastic/elasticsearch is the official Node.js client maintained by Elastic for talking to Elasticsearch clusters. It wraps the full Elasticsearch REST API in a single Client class, with every endpoint (search, index, bulk, ingest pipelines, ES|QL, security, and more) exposed as a typed method generated directly from Elasticsearch’s API specification, so the client stays in lockstep with server releases.

Under the hood it delegates connection management, retries, sniffing, and serialization to its companion @elastic/transport package, while this package layers on Elasticsearch-specific ergonomics: cloud ID and API key authentication, OpenTelemetry-based observability, child clients for per-request overrides, and a set of helper utilities (scrollSearch, msearch, bulk, and an Apache Arrow-backed ES|QL helper) that turn common multi-request patterns into single async calls or iterators.

Because versioning tracks the Elastic Stack rather than semver-for-semver-sake, the client publishes a version for every major/minor line of Elasticsearch (7.x, 8.x, 9.x) and documents exactly which server versions each client major is compatible with, plus a supported aliasing trick for running multiple client versions side by side in one project.

What You Get

  • A fully typed Client class covering the entire Elasticsearch REST API (index, search, ingest, security, ES|QL, and more), generated from Elasticsearch’s own API spec so method signatures track server capabilities
  • Pluggable connection pooling (WeightedConnectionPool, CloudConnectionPool) and an optional SniffingTransport for cluster node discovery, both inherited from @elastic/transport
  • Built-in auth support for basic auth, API keys, bearer tokens, and Elastic Cloud IDs, so connecting to self-managed or Cloud clusters needs only a config object
  • Helper utilities (scrollSearch/scrollDocuments, msearch, bulk, and an ES|QL-to-records/Arrow helper) that wrap multi-step Elasticsearch interaction patterns into single async iterables or promises
  • First-class TypeScript types for every request/response shape, plus dual CJS/ESM builds so the client works in both module systems out of the box
  • OpenTelemetry-based observability hooks and a child-client API for overriding headers or options on a per-request basis without mutating the parent client

Common Use Cases

  • Indexing and searching application data (logs, product catalogs, documents) from a Node.js backend against a self-hosted or Elastic Cloud cluster
  • Bulk-loading or re-indexing large datasets using the bulk helper, which batches documents and handles retries/backpressure automatically
  • Building analytics or reporting features on top of ES|QL queries, using the ES|QL helper to get typed records or an Apache Arrow table back from a query
  • Paginating through large result sets with scrollSearch/scrollDocuments instead of hand-rolling scroll-context management
  • Running many independent searches efficiently in one round trip via the msearch helper, useful for dashboards that need several queries per page load

Under The Hood

Architecture

The package centers on a single Client class (src/client.ts) that composes a Transport, a Serializer, and a ConnectionPool implementation imported from the companion @elastic/transport package, then mixes in a generated API surface (src/api/) that attaches one typed method per Elasticsearch endpoint. A SniffingTransport subclass (src/sniffingTransport.ts) swaps in cluster-discovery behavior when sniffing is enabled, and a separate Helpers class (src/helpers.ts) wraps the raw client in higher-level async iterables (scrollSearch, msearch, bulk, ES|QL) that internally just call back into the same Client instance. Because the low-level HTTP/connection concerns live entirely in @elastic/transport, changing that core abstraction would ripple through every client method, but this package’s own responsibility is narrow and well-separated: typed endpoint surface plus convenience helpers on top of a transport it does not implement itself.

Tech Stack

The client is TypeScript-first (98%+ of the codebase), built via tsc into dual CJS (lib/) and ESM (esm/) outputs from tsconfig.json/tsconfig.esm.json, and depends directly on @elastic/transport (its own connection pooling and retry engine) plus tslib for helper runtime support. apache-arrow is an optional peer dependency, loaded lazily via a require inside loadArrow() in helpers.ts, only when the ES|QL Arrow helper is actually used. Tooling includes ESLint (via neostandard), c8/tap for coverage-gated testing, and a renovate.json for automated dependency updates, with the engines field pinning a Node.js >=22 requirement.

Code Quality

Tests live under test/unit, test/integration, test/esm, and test/fuzz, using the tap test runner with c8 coverage thresholds enforced in the test npm script (96% statements, 90% branches, 96% lines, 91% functions) — a notably strict, explicitly enforced bar rather than an aspirational one. Unit tests are organized per-module (client.test.ts, sniffingTransport.test.ts, helpers/scroll.test.ts, helpers/bulk.test.ts, helpers/msearch.test.ts, helpers/esql.test.ts), and the suite spins up real HTTP servers via a shared buildServer test utility rather than mocking at the network boundary, giving reasonably realistic coverage of connection and retry paths. Types are strict throughout, and CI runs a nodejs.yml workflow plus a separate integration-test pipeline on Buildkite.

API Design The public surface favors a single Client constructor accepting cloud ID, API key, or basic-auth options directly, keeping getting-started boilerplate minimal, while every generated endpoint method mirrors Elasticsearch’s own request/response naming so users familiar with the REST API transfer that knowledge directly. The helper layer (scrollSearch, bulk, msearch, ES|QL) exists specifically to remove boilerplate around multi-request Elasticsearch patterns that would otherwise require manual state tracking (scroll IDs, batching, backpressure), turning them into async iterables or promise-returning calls consistent with idiomatic Node.js usage.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers