npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

elasticsearch-fetch

v0.9.1

Published

A lightweight, fetch-based alternative to the heavy Elasticsearch SDK

Readme

elasticsearch-fetch

NPM Link Language Build Status Code Coverage Gzipped Size Tree Shakeable ISC License

elasticsearch-fetch is a pure ESM, 11 times smaller fetch-based alternative to the Elasticsearch SDK (on npm as @elastic/elasticsearch). It works on any modern ESM runtime that supports fetch including Node.js 18+, Deno, Bun, and Edge Worker runtimes (e.g. Cloudflare Workers).

npm install elasticsearch-fetch

Table of Contents

Usage

There are three ways to use elasticsearch-fetch depending on whether you prefer compatibility or build size.

File Sizes

elasticsearch-fetch can range anywhere between 4kb and 22kb minzipped in your build. But compare that to @elastic/elasticsearch's build size of 257kb minzipped. That's a bundle size savings of 92% to 98%!

Option 1 - Full SDK - 22kb minzipped

You can use elasticsearch-fetch with all 567 of the operations available in the @elastic/elasticsearch SDK:

import { Client } from 'elasticsearch-fetch';

const client = new Client({
  node: 'http://localhost:9200',
  auth: {
    username: process.env.ES_USERNAME,
    password: process.env.ES_PASSWORD,
  },
});

await client.indices.create({
  index: 'tweets',
  mappings: {
    properties: {
      id: { type: 'integer' },
      text: { type: 'text' },
      user: { type: 'keyword' },
      time: { type: 'date' }
    }
  }
}, { ignore: [400] });

const bulkResponse = await client.bulk({ refresh: true, operations });
const count = await client.count({ index: 'tweets' });

Option 2 - Functional tree-shaken: your build includes only what you use

import { createTransport, indicesCreate, bulk, count } from 'elasticsearch-fetch/functions';

const tx = createTransport({
  node: 'http://localhost:9200',
  auth: {
    username: process.env.ES_USERNAME,
    password: process.env.ES_PASSWORD,
  },
});

await indicesCreate(tx, {
  index: 'tweets',
  mappings: {
    properties: {
      id: { type: 'integer' },
      text: { type: 'text' },
      user: { type: 'keyword' },
      time: { type: 'date' }
    }
  }
}, { ignore: [400] });

const bulkResponse = await bulk(tx, { refresh: true, operations });
const count = await count(tx, { index: 'tweets' });

Option 3 (Recommended) - Custom SDK: build your own client from presets and/or individual endpoints

Register exactly the endpoints you want, and client is typed to match — only the registered methods autocomplete and type-check.

import { Client, presetCrud, presetEql } from 'elasticsearch-fetch/presets';
import { clusterHealth, clusterInfo } from 'elasticsearch-fetch/functions';

const client = new Client(
  {
    node: 'http://localhost:9200',
    auth: {
      username: process.env.ES_USERNAME,
      password: process.env.ES_PASSWORD,
    },
  },
  {
    ...presetCrud,
    ...presetEql,
    'cluster.health': clusterHealth,
    'cluster.info': clusterInfo,
  }
);

await client.bulk({ refresh: true, operations });
await client.eql.search({ index: 'tweets', query: 'process where true' });
await client.cluster.health();

You can also register additional endpoints after construction with client.register({ ... }), though methods added this way won't be reflected in client's TypeScript type.

Presets

Import any combination of the following from elasticsearch-fetch/presets

  • presetCrud - All 39 CRUD operations
  • presetSchema - info, all 27 cat.* operations, and all 71 indices.* operations
  • presetTasks - all 3 tasks.* operations
  • presetIngest - all 5 ingest.* operations
  • presetEql - all 4 eql.* operations
  • presetEsql - all 15 esql.* operations
  • presetSql - all 6 sql.* operations
  • presetAsyncSearch - all 4 asyncSearch.* operations

Example minzipped build sizes:

  • Monolithic @elastic/elasticsearch - 257kb
  • Full elasticsearch-fetch - 22kb
  • presetCrud - 4kb
  • presetCrud + presetSchema - 7kb

Auth

Auth is compatible with the official SDK. You can specify auth in 7 different ways.

  1. auth: undefined - Server requires no auth
  2. auth: { username: 'user', password: 'pass' } - Username and password
  3. auth: { bearer: 'abc123' } - Bearer token
  4. auth: { apiKey: 'abc123' } - API Key
  5. process.env.ELASTICSEARCH_USERNAME && process.env.ELASTICSEARCH_PASSWORD - Env vars for username and password
  6. process.env.ELASTICSEARCH_BEARER - Env var for bearer token
  7. process.env.ELASTICSEARCH_API_KEY - Env var for API key

Connection Options

node is optional when creating a Client or a transport with createTransport(). If omitted, it falls back to process.env.ELASTICSEARCH_NODE, and if that's not set either, it defaults to http://localhost:9200.

import { Client } from 'elasticsearch-fetch';

// equivalent to new Client({ node: process.env.ELASTICSEARCH_NODE ?? 'http://localhost:9200' })
const client = new Client();

TypeScript Types

Every operation in elasticsearch-fetch—whether you use the full SDK, a tree-shaken function, or a custom preset-built client—is typed using the same request/response interfaces as @elastic/elasticsearch, exposed under its estypes namespace. elasticsearch-fetch doesn't redefine or duplicate Elasticsearch's types; it imports estypes as a type-only import and reuses it directly, so @elastic/elasticsearch only needs to be present for its type definitions — none of its runtime code ends up in your bundle.

In practice this means you get the same editor autocomplete and compile-time checking you'd get from the official SDK:

import { Client } from 'elasticsearch-fetch';

const client = new Client({ node: 'http://localhost:9200' });

// TypeScript knows the shape of `count`'s params...
await client.count({ index: 'tweets', min_score: 1.5 });

// ...and flags mistakes before you run the code
await client.count({ index: 'tweets', min_score: '1.5' }); // Error: string is not assignable to number
await client.count({ indx: 'tweets' }); // Error: `indx` does not exist; did you mean `index`?

// The resolved response is typed too, so properties autocomplete
const result = await client.count({ index: 'tweets' });
console.log(result.count); // number

Each generated function is typed as (transport, params: estypes.XRequest, options?) => Promise<estypes.XResponse> for its operation (for example count's params/response types are estypes.CountRequest/estypes.CountResponse). When you build a client from Client, presets, or register(), those per-function types flow through into the shape of client, so only the methods you actually registered appear on it, each with its own accurately typed params and response — there's no generic "any operation" signature to fall back on.

All Operations

For a list of all methods with associated links to Elasticsearch's online documentation see one of the following:

How it Works

Elasticsearch releases a schema file on GitHub that includes all server methods. They generate the JavaScript SDK programmatically based on that schema. Each generated function includes runtime validation which takes up a lot of space. For instance the TypeScript source code of bulk is 2768 bytes in @elastic/elasticsearch, but 352 bytes in elasticsearch-fetch/functions.

So elasticsearch-fetch includes a small fetch-based transport layer instead of the node-networking transport layer of @elastic/elasticsearch. But it also builds its dist from Elasticsearch's own schema file.

Contributions

Contributions through GitHub issues and pull requests are welcome.

Bun is required for testing and building the elasticsearch-fetch package.