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

@ncbijs/eutils

v0.0.0

Published

Spec-compliant HTTP client for all 9 NCBI E-utilities

Downloads

187

Readme


Why

NCBI E-utilities power access to PubMed, PMC, and 30+ biomedical databases. But the raw HTTP API has sharp edges:

  • Rate limits (3 req/s, or 10 with an API key) that silently block you if exceeded
  • XML responses that vary structurally across 9 different endpoints
  • POST switching required when ID lists or query terms exceed URL length limits
  • History Server pagination for large result sets that requires coordinating WebEnv tokens

@ncbijs/eutils handles all of this behind a typed, promise-based API. You call methods, you get typed results.

Install

npm install @ncbijs/eutils

Quick start

import { EUtils } from '@ncbijs/eutils';

const eutils = new EUtils({
  tool: 'my-research-app', // Required by NCBI usage policy
  email: '[email protected]', // Required by NCBI usage policy
  apiKey: 'your-ncbi-api-key', // Optional: raises rate limit from 3 to 10 req/s
});

// Search PubMed
const search = await eutils.esearch({
  db: 'pubmed',
  term: 'CRISPR gene therapy',
  retmax: 5,
});
console.log(`Found ${search.count} results`);
console.log('Top UIDs:', search.idList);

// Fetch full records
const xml = await eutils.efetch({
  db: 'pubmed',
  id: search.idList.join(','),
  rettype: 'abstract',
  retmode: 'xml',
});

API

Constructor

new EUtils(config: EUtilsConfig)

| Parameter | Type | Required | Description | | ------------ | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- | | tool | string | Yes | Application name (NCBI usage policy) | | email | string | Yes | Developer contact email | | apiKey | string | No | NCBI API key (10 req/s vs 3 req/s) | | maxRetries | number | No | Retry count with exponential backoff (default: 3) |

Methods

All methods return a Promise. The rate limiter and retry logic apply automatically.

esearch(params)ESearchResult

Search an Entrez database and return matching UIDs.

const result = await eutils.esearch({
  db: 'pubmed',
  term: 'asthma treatment',
  usehistory: 'y',
  retmax: 100,
  sort: 'pub_date',
});
// result.count, result.idList, result.webEnv, result.queryKey

efetch(params)string

Fetch records in the requested format. Returns the raw response string (XML, text, etc.).

const xml = await eutils.efetch({
  db: 'pubmed',
  id: '38000001,38000002',
  rettype: 'abstract',
  retmode: 'xml',
});

esummary(params)ESummaryResult

Retrieve document summaries (DocSums) for a list of UIDs.

const result = await eutils.esummary({
  db: 'pubmed',
  id: '38000001',
  retmode: 'json',
});
// result.docSums[0].uid, result.docSums[0]['Title']

epost(params)EPostResult

Post UIDs to the History Server for use in subsequent queries.

const posted = await eutils.epost({
  db: 'pubmed',
  id: '38000001,38000002,38000003',
});
// posted.webEnv, posted.queryKey

elink(params)ELinkResult

Discover links between Entrez databases. Supports all 9 cmd variants: neighbor, neighbor_score, neighbor_history, acheck, ncheck, lcheck, llinks, llinkslib, prlinks.

const result = await eutils.elink({
  db: 'pubmed',
  dbfrom: 'pubmed',
  id: '38000001',
  cmd: 'neighbor',
});
// result.linkSets[0].linkSetDbs[0].links

einfo(params?)EInfoResult

List all Entrez databases (no params) or get metadata for a specific database.

// List all databases
const all = await eutils.einfo();
// all.dbList: ['pubmed', 'protein', ...]

// Database detail
const detail = await eutils.einfo({ db: 'pubmed' });
// detail.dbInfo.fieldList, detail.dbInfo.linkList

espell(params)ESpellResult

Check spelling of a search term.

const result = await eutils.espell({ db: 'pubmed', term: 'asthmaa' });
// result.correctedQuery === 'asthma'

egquery(params)EGQueryResult

Query all Entrez databases at once and return per-database hit counts.

const result = await eutils.egquery({ term: 'BRCA1' });
// result.eGQueryResultItems: [{ dbName: 'pubmed', count: 25000 }, ...]

ecitmatch(params)ECitMatchResult

Match citation strings to PubMed IDs.

const result = await eutils.ecitmatch({
  bdata: 'Ann Intern Med|1998|129|103|Feigelson HS|key1|',
});
// result.citations[0].pmid === '9652966'

efetchBatches(params)AsyncIterableIterator<string>

Auto-paginate large result sets via the History Server.

// Fetch 10,000 records in batches of 500
const search = await eutils.esearch({
  db: 'pubmed',
  term: 'COVID-19 vaccine',
  usehistory: 'y',
});

for await (const batch of eutils.efetchBatches({
  db: 'pubmed',
  WebEnv: search.webEnv,
  query_key: search.queryKey,
  rettype: 'abstract',
  retmode: 'xml',
  batchSize: 500,
})) {
  // Process each batch of XML records
  processBatch(batch);
}

searchAndFetch(params)AsyncIterableIterator<string>

Convenience pipeline: ESearch with History Server → stream EFetch batches. Combines esearch + efetchBatches in a single call.

for await (const batch of eutils.searchAndFetch({
  db: 'pubmed',
  term: 'CRISPR gene therapy',
  rettype: 'abstract',
  retmode: 'xml',
  batchSize: 500,
})) {
  processBatch(batch);
}

searchAndSummarize(params)AsyncIterableIterator<ESummaryResult>

Convenience pipeline: ESearch with History Server → stream ESummary batches.

for await (const batch of eutils.searchAndSummarize({
  db: 'pubmed',
  term: 'COVID-19 vaccine',
  retmode: 'json',
  batchSize: 100,
})) {
  for (const docSum of batch.docSums) {
    console.log(docSum.uid, docSum['Title']);
  }
}

Error handling

import { EUtils, EUtilsHttpError } from '@ncbijs/eutils';

try {
  await eutils.esearch({ db: 'pubmed', term: 'test' });
} catch (err) {
  if (err instanceof EUtilsHttpError) {
    console.error(`HTTP ${err.statusCode}: ${err.responseBody}`);
  }
}

The client automatically retries on HTTP 429, 500, 502, 503 and network errors (DNS failures, connection resets) with exponential backoff + jitter.

Rate limiting

Rate limiting is automatic. The built-in token bucket enforces:

  • 3 requests/second without an API key
  • 10 requests/second with an API key

Concurrent calls from the same EUtils instance are queued in FIFO order. No manual throttling needed.

Known limitations

PMC ESearch/EPost 10K record cap (February 2026)

As of early February 2026, NCBI restricts ESearch and EPost for the PMC database (db=pmc):

  • ESearch: retmax must be ≤ 10,000, and retstart + retmax must be ≤ 10,000
  • EPost: accepts a maximum of 10,000 PMCIDs per request

This only affects PMC (db=pmc). PubMed and all other databases are unaffected.

For queries that return more than 10,000 PMC results, break your search into smaller batches or use more specific search terms. See NCBI's announcement for details.

Spec compliance

Every method maps directly to an NCBI E-utility endpoint:

| Method | Endpoint | Spec | | ----------- | --------------- | ---------------------------------------------------------------------------- | | esearch | esearch.fcgi | ESearch | | efetch | efetch.fcgi | EFetch | | esummary | esummary.fcgi | ESummary | | epost | epost.fcgi | EPost | | elink | elink.fcgi | ELink | | einfo | einfo.fcgi | EInfo | | espell | espell.fcgi | ESpell | | egquery | egquery.fcgi | EGQuery | | ecitmatch | ecitmatch.cgi | ECitMatch |