# typesense-js: the JavaScript client for Typesense search

> typesense-js is the JavaScript and TypeScript client for the Typesense HTTP API, usable from a server or a browser, with timeouts, abort signals, a compatibility table and companion plugins for Gatsby and Firebase. The catch is that browser use means shipping a search-only API key to the client.

**typesense/typesense-js** — JavaScript / TypeScript client for Typesense

- Repository: https://github.com/typesense/typesense-js
- Website: https://typesense.org/docs/api
- Stars: 573 · Forks: 101
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/typesense-typesense-js

## A typed wrapper over the Typesense HTTP API

typesense-js is the JavaScript and TypeScript client library for accessing the Typesense HTTP API. The scope is narrow and worth stating plainly: this is a client, not a search engine. It does not index anything, it does not rank anything, and it has no opinion about relevance. It gives a JavaScript or TypeScript program a typed way to talk to a Typesense server that is doing that work.

The primary language of the repository is TypeScript, and the type declarations ship with the package. The package.json entry points tell the story of how it is meant to be consumed: main points at lib/Typesense.js for the server build, types points at lib/Typesense.d.ts, and there is a browser field that maps crypto, http and https to false, which is the standard way to tell a bundler that those Node built-ins are not available in a browser context and should not be pulled in.

The audience is a developer with a Typesense deployment who needs search from a Node service, a React front end, or both. The documentation lives off the repository at typesense.org/docs/api, and the README points at the test directory as a good place to see how the library works internally, which is a reasonable suggestion for a client whose behaviour is mostly about request shapes.

The repository layout also shows a conventional modern toolchain: webpack.config.js for the browser bundle, vitest.config.ts with the browser mode package for tests, eslint.config.cjs, tsconfig.json and tsconfig.test.json, and a pnpm workspace file.

## Two build outputs, one for servers and one for browsers

The build arrangement is described in one paragraph of the README and it is the clearest thing about the project. The source in src is written in ES6, and at build time it is transpiled to ES5 and generates two artifacts. One, in lib, is used on the server side, and the other, in dist, uses Browserify and can be used on the client side.

That is why the install instructions offer two options, and why they are not equivalent. The npm path gives you the package, and the browser path gives you a single minified file:

```html
<script src="dist/typesense.min.js"></script>
```

or through jsDelivr:

```html
<script src="https://cdn.jsdelivr.net/npm/typesense@3/dist/typesense.min.js"></script>
```

The jsDelivr URL pins the major version to 3, so a script tag user follows the v3 line rather than the latest major automatically. That is a deliberate choice by the maintainers for the unpinned CDN case, but it means the script tag path and the npm path can drift apart if you upgrade one and not the other.

The published files list in package.json is lib/, dist/ and src/, so the TypeScript source ships to npm as well, which is convenient if you want to read the implementation of a method rather than guess at it.

## Installing from npm and the peer dependency decision

The npm installation is two commands, and the second one is the interesting part:

```sh
npm install --save typesense
```

```sh
npm install --save @babel/runtime
```

The README explains the reasoning for asking you to install @babel/runtime yourself rather than taking it as a dependency. It is a very common dependency among many JavaScript libraries, and instead of each library adding it independently, which causes multiple instances to be installed and increases bundle size, Babel's recommendation is that libraries ask users to install it once as a direct dependency, so there is only one copy for the whole project. The README also notes that in some cases your JavaScript framework might already include it as a dependency.

The practical consequence is a small amount of manual work in exchange for a smaller bundle, and the risk that a project that skips the second command ends up with duplicated runtime copies.

The release record is regular and recent: v3.2.0 on 2026-10-19, v3.1.1 on 2026-10-05 and v3.1.0 on 2026-09-25, with the last push on 2026-10-19. For development, the README says that after checking out the repo you run pnpm install to install dependencies and then pnpm test:local to run the linter and tests, and releases are cut with the np package.

## Global timeout and per-request abort signals

The client supports both a global timeout configuration and per-request abort signals, and the README gives an example of each. The global form is a property on the client configuration:

```javascript
const client = new Typesense.Client({
  nodes: [{ host: "localhost", port: "8108", protocol: "http" }],
  apiKey: "xyz",
  connectionTimeoutSeconds: 30, // 30 second timeout for all requests
});
```

The per-request form is an AbortController passed as a second argument to the call:

```javascript
// Search with 5-second timeout
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);

const results = await client.collections("books").documents().search(
  {
    q: "*",
    query_by: "title",
  },
  { abortSignal: controller.signal },
);
```

The point of having both is granularity. A connection timeout on the client covers every request the instance makes, which is a sensible baseline. The abort signal lets one slow query fail fast without changing the behaviour of everything else, which matters when a search sits inside a request handler that has its own deadline.

One gap the README flags itself: the import() operation does not support abort signals or timeout configuration, as it is designed to run to completion. That is a sensible design, since an import that is interrupted halfway leaves the collection in a partial state, but it also means the abort mechanism does not cover the heaviest operation the client performs. The full list of client configuration options is in src/Typesense/Configuration.ts.

## A search-only key is the price of client-side search

The README carries a warning that deserves to be read before any code is written, and it sits in the usage section rather than in a security section. When using this library in a browser, use an API key that only allows search operations instead of the master API key, and the README points at doc/examples/server/keys.js for an example of how to generate a search-only API key.

This is the central design tension of the library, and it is not a minor one. The same client runs in Node and in the browser, but the trust model is completely different. A Node server holds credentials that stay on the machine. A browser bundle holds a key that anyone can read out of the devtools network tab, so the key's capability has to be limited to searching.

The mechanism is a scoped key generated server-side, and the example path in the repository shows how to produce it. The client-side usage then looks identical to the server-side usage, which is exactly what makes it easy to get wrong, because a working example that swaps in a master key will work perfectly and expose the whole cluster.

If you are not willing to run the key generation step and distribute scoped keys, the safe conclusion is to keep the client on the server and proxy the search from your own API. That is more code and one more network hop, and it is the configuration the master key warning is steering you away from.

## Matching the client version to the server version

The compatibility table in the README is the single most useful piece of documentation in the project, because it removes the guesswork from version pinning. The rule it states is that newer versions of the client library maintain backwards compatibility with older versions of the server library.

The table maps server versions to client versions in one direction only. A server at v30.0 or newer pairs with client v3.0.0 or newer, a server at v27.0.rc20 pairs with client v2.0.0 or newer, a server at v0.26.0.rc38 pairs with client v1.8.0 or newer, and the rows step down through v0.25.0 with v1.7.0, v0.24.0 with v1.5.0, v0.23.0 with v1.3.0, v0.21.0 with v0.14.0, v0.20.0 with v0.12.0, v0.19.0 with v0.11.0, v0.18.0 with v0.10.0, v0.17.0 with v0.9.0, v0.16.0 with v0.8.0, v0.15.0 with v0.7.0, v0.12.1 with v0.5.0, v0.12.0 with v0.4.7, and a server at v0.11 or below with a client at v0.3.0 or below.

Reading it in the other direction is the operationally useful habit. If you pin the client at v2.x, you know you need a server at v27.0.rc20 or newer. If you are on a recent server, the client line you want is v3.x, which is where the current releases sit.

Note also that the table stops at v30.0 for the server, so a server newer than that has no stated pairing in the README, and the client version requirement for it is not documented here.

## The ecosystem around the client

The client is the core, and the repository points at a set of things built on top of it, which is the useful way to judge how much of the work you would otherwise write yourself.

For site generation there is a GatsbyJS plugin, which uses typesense-js behind the scenes to automatically push your site data to Typesense when you build your site. For application data there is a Firebase extension that uses typesense-js behind the scenes to automatically push your Firestore data to Typesense. For the user interface there is Typesense-InstantSearch.js, an adapter that uses typesense-js and provides UI components for building instant search experiences.

The pattern is consistent across all three. Each one is a thin integration that uses the client rather than replacing it, which means the API knowledge you learn here still applies when you adopt the plugin, and you can drop down to the client whenever the plugin does not cover your case.

The repository also holds a doc/examples directory with inline-comment examples covering how to use the client, and the README explains how to run them from the repo root, which is a practical way to see a real request sequence rather than reading documentation about one:

```bash
pnpm typesenseServer
node doc/examples/server/bulkImport.js
```

The client is licensed Apache 2.0, with the author listed as Typesense, Inc., which matters for anyone embedding it in a commercial front end, since there is no copyleft obligation and no attribution requirement beyond the licence text.

## Conclusion

Adopt typesense-js if your application already runs a Typesense server and you want typed access to its HTTP API from Node or the browser, and you are prepared to issue a search-only API key to any client-side code. Do not adopt it if you need full-text ranking or fuzzy matching beyond what Typesense itself provides, since this is a client, not a search engine, and do not use it in the browser with a master key. Verify first that the client version you pick matches the server version in the compatibility table, that your bundler handles the package's browser field for crypto, http and https, and that your key generation follows the server-side example in doc/examples/server/keys.js.

## FAQ

### How do I install typesense-js?

Run npm install --save typesense, then install the peer dependency with npm install --save @babel/runtime so the project has a single copy of the Babel runtime. In a browser you can instead load the minified bundle with a script tag pointing at dist/typesense.min.js or the jsDelivr URL.

### Can typesense-js be used in the browser?

Yes, the library can be used both on the server side and on the client side, and the build produces a Browserify bundle in dist for that purpose. The README warns that in a browser you must use an API key that only allows search operations rather than the master key.

### How do I set a timeout on a typesense-js request?

Set connectionTimeoutSeconds on the client configuration for a global timeout on all requests, or pass an AbortSignal in the second argument of an individual call. The import() operation does not support either, because it is designed to run to completion.

### Which typesense-js version works with my Typesense server?

The README states that newer client versions stay compatible with older server versions, and gives a table: server v30.0 or newer needs client v3.0.0 or newer, server v27.0.rc20 needs client v2.0.0 or newer, and older server versions map down to v1.x and v0.x client lines.

### Does typesense-js have official framework integrations?

The README points to a GatsbyJS plugin that pushes site data to Typesense at build time, a Firebase extension that pushes Firestore data, and Typesense-InstantSearch.js for ready-made instant search UI components. Each of them uses typesense-js underneath.

## Sources

- [License: Apache-2.0](https://github.com/typesense/typesense-js/blob/master/LICENSE)
- [Project website](https://typesense.org/docs/api)
- [README](https://github.com/typesense/typesense-js/blob/master/README.md)
- [Releases](https://github.com/typesense/typesense-js/releases)
- [typesense/typesense-js on GitHub](https://github.com/typesense/typesense-js)

---

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