Library / SDK
pocketbase/js-sdk avatar
pocketbase/js-sdk

pocketbase/js-sdk: the official JavaScript client for PocketBase

PocketBase JavaScript SDK

2,942 stars205 forksTypeScriptMIT

At a glance

What is it?
The official JavaScript SDK for PocketBase, published on npm as pocketbase. It wraps the PocketBase Web API for browsers and Node, and its caveats section is where the real decisions live.
Who is it for?
Adopt pocketbase/js-sdk when your client already talks to a PocketBase instance and you want the official client rather than hand-rolled fetch calls: it gives you pb.authStore, pb.filter for escaping, normalized ClientResponseError, and auto cancellation without writing any of it yourself.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 25 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What pocketbase/js-sdk is for

PocketBase ships a Web API, and this repository is the official JavaScript client for it. The README describes it as the "Official JavaScript SDK (browser and node) for interacting with the PocketBase API". That sentence sets the boundary: the SDK is a client, not a backend, and it is not useful without a running PocketBase server to point at.

The audience is anyone writing JavaScript that talks to that server. In the browser that means auth flows, record lists, file uploads and realtime subscriptions. On the server it means the same calls from Node, Deno or Bun, with one extra responsibility the README calls out directly: when a list query accepts a filter string from an untrusted user, the SDK's pb.filter helper escapes the values before they reach the query. That is a server-side concern specifically, and the README says as much, noting that on the client side injection "is not much of an issue".

So the project solves a narrow problem well: it removes the boilerplate of talking to one specific API, and it centralizes a few decisions (token storage, error shape, request cancellation) that every hand-written client gets wrong at least once.

The auth store is the main design decision

Most of the SDK is a thin wrapper over HTTP endpoints. The part that carries real design weight is pb.authStore, and the README spends more space on it than on any other caveat.

The default is LocalAuthStore. It uses the browser's LocalStorage when available and falls back to runtime memory otherwise. That fallback is the important half of the sentence: in an environment without LocalStorage, a page refresh or a service restart means the user has to authenticate again. The default store also syncs auth state across browser tabs, which is behaviour you would otherwise write yourself and get subtly wrong.

The README then flags a Deno-specific trap: Deno supports LocalStorage, but unlike a browser where the client is the only user, Deno's LocalStorage is by default shared by all clients making requests to your server. That is a security-relevant default, not a performance note, and it is the kind of thing that is easy to miss when porting a browser snippet to a Deno server.

For React Native the README points at AsyncAuthStore, a helper for integrating with third-party async storage. The SDK also allows a custom auth store. The trade-off is that the further you move from LocalAuthStore, the more of the cross-tab and persistence behaviour you own yourself.

Installing pocketbase from npm and making a first call

The README gives npm as the Node installation path. The package name on npm is pocketbase, and the repository's package.json confirms the version tracked in this repository is 0.28.1.

bash
npm install pocketbase --save

After install, import the default export and point it at your server. The README's usage example uses http://127.0.0.1:8090, which is the local PocketBase address shown in the documentation.

js
import PocketBase from 'pocketbase';

const pb = new PocketBase('http://127.0.0.1:8090');

const userData = await pb.collection('users').authWithPassword('[email protected]', '123456');

const result = await pb.collection('example').getList(1, 20, {
    filter: 'status = true && created > "2022-08-01 10:00:00"'
});

If you are on CommonJS, the README shows the alternative import path as require('pocketbase/cjs'). The exports map in package.json confirms three entry points: the default ESM build, ./cjs and ./umd. For a browser without a bundler, the README loads dist/pocketbase.umd.js via a script tag and then constructs new PocketBase("https://example.com").

Two runtime caveats apply before this code runs anywhere unusual. On Node below 17 you need a fetch polyfill, and the README recommends cross-fetch. Node also has no native EventSource, so realtime subscriptions need a polyfill (eventsource on the server, react-native-sse for React Native), assigned to global.EventSource.

Filter binding, file upload and the error shape

Three behaviours are worth knowing before you write your first query.

Filter binding. pb.filter(expr, params) takes a filter string with {:paramName} placeholders and an object of values, and returns an escaped filter string. The README's example turns the expression "title ~ {:title} && (totalA = {:num} || totalB = {:num})" with { title: "te'st", num: 123 } into a properly escaped query. The supported parameter types are listed explicitly: string, number, boolean, null, undefined (stringified as null), Date objects, and everything else via JSON.stringify(). If you pass a type outside that list, you are relying on JSON.stringify() to produce something the server accepts, which is a reasonable assumption but not a documented guarantee for arbitrary objects.

File upload. PocketBase accepts multipart/form-data, so you can pass either a FormData instance or a plain object whose properties are File or Blob values. The README shows both; the plain-object form is converted to FormData behind the scenes.

Error handling. Every service returns a Promise, so .then/.catch and try/catch both work. Errors are normalized into a ClientResponseError with public fields url, status, response, isAbort and originalError. The isAbort flag matters because of the auto cancellation behaviour: the SDK cancels duplicate in-flight requests, and a cancelled request surfaces as an error you should not treat as a failure. Checking isAbort before showing an error message is the difference between a clean UI and spurious toasts.

Limitations and where this SDK is the wrong tool

The SDK is a client for one server. If your backend is not PocketBase, none of this applies, and no amount of configuration changes that.

The runtime requirements are the sharper constraint. Node below 17 needs a fetch polyfill, and realtime subscriptions need an EventSource polyfill on Node and on React Native. The README states both plainly, which is good, but it means a plain Node service that wants live updates carries two extra dependencies before it does anything.

The auth store fallback is the quiet failure mode. LocalAuthStore falls back to memory when LocalStorage is unavailable. Nothing throws, nothing warns, and the symptom appears later as users being logged out on refresh. If you are running in an unusual runtime, confirm which path you are on rather than assuming persistence.

The README does not document rollback or an upgrade path between SDK versions. There is a CHANGELOG.md at the repository root, and the README's own table of contents does not link to it. For a library whose version is pinned in package.json at 0.28.1 and whose recent releases include 0.28.0 and 0.27.3, that is a gap: you are expected to read the changelog yourself before bumping, and the README gives you no guidance on whether a minor bump is safe.

Finally, the README's own scope note is worth taking literally. The filter escaping guidance is aimed at server-side list queries accepting untrusted input. If you are passing user-supplied filter strings from a browser, the SDK protects the string it builds, but the README frames client-side injection as a low concern rather than a solved one.

How it compares to calling the API directly

The obvious alternative is fetch or axios against the PocketBase Web API yourself. The difference is not convenience, it is which behaviours you reimplement.

With raw fetch you write your own token persistence, your own cross-tab sync, your own request cancellation for duplicate in-flight calls, and your own error normalization. The SDK ships all four, and the README documents each as a named caveat: LocalAuthStore with multi-tab sync, auto cancellation, and ClientResponseError with its five public fields. The pb.filter escaping helper is the one piece that is genuinely awkward to reproduce correctly, because it has to handle strings, numbers, booleans, null, undefined, Date objects and arbitrary values through JSON.stringify().

On the other side, a hand-written client has no polyfill requirements. If you only ever call getList and create from a modern Node runtime, the SDK's EventSource and fetch caveats are overhead you do not need, and a small fetch wrapper may be less to maintain. The honest split is this: if you use auth, realtime or user-supplied filters, the SDK earns its place. If you make a handful of read calls from a controlled server, it may not.

Maintenance, licence and upgrade cost

The repository is not archived. Its last push was on 2026-09-05, and the most recent release listed is v0.28.1 on the same date, following v0.28.0 on 2026-08-19 and v0.27.3 on 2026-08-13. The release cadence visible in those three entries is roughly weekly to biweekly, which is consistent with a maintained client tracking a server project.

The licence is MIT, stated in package.json and present as LICENSE.md at the repository root. MIT is permissive: it allows use, modification and redistribution with the licence and copyright notice retained. That is a statement about the licence text, not legal advice for your situation.

The upgrade cost is where the material is thin. The repository has a CHANGELOG.md, and the README does not reference it or describe any migration procedure. The version is 0.28.1, still in the 0.x range, where semver permits breaking changes in minor releases. Treat every bump as something to read up on rather than something to take on faith. The repository layout is conventional (src/, dist/, tests/, rollup.config.mjs, vite.config.ts), and the build script in package.json is rollup -c, with prepublishOnly running the build, so the published dist files are generated rather than committed by hand.

Editorial conclusion

Adopt pocketbase/js-sdk when your client already talks to a PocketBase instance and you want the official client rather than hand-rolled fetch calls: it gives you pb.authStore, pb.filter for escaping, normalized ClientResponseError, and auto cancellation without writing any of it yourself. Do not adopt it if you are not running a PocketBase backend, or if your target runtime is Node below 17 without a fetch polyfill and without EventSource, because realtime subscriptions will not work until you load one. Before you commit, verify three things in your own environment: which auth store your runtime actually resolves to (LocalAuthStore falls back to memory when LocalStorage is missing, so a page refresh logs the user out), whether your bundler picks the ESM, CJS or UMD build from the exports map, and whether Deno's shared LocalStorage is acceptable for your deployment. The README documents none of the upgrade path between SDK versions, so read CHANGELOG.md before bumping the dependency.

Frequently asked questions

How do I install pocketbase/js-sdk?

Install it from npm with npm install pocketbase --save. For a browser without a bundler, the README also shows loading dist/pocketbase.umd.js with a script tag, or importing dist/pocketbase.es.mjs as an ES module.

Does pocketbase/js-sdk work in Node.js?

Yes, it is described as the official SDK for browser and node. On Node below 17 you need a fetch polyfill such as cross-fetch, and realtime subscriptions require an EventSource polyfill because Node has no native implementation.

How does pocketbase/js-sdk handle authentication tokens?

It keeps the token and auth model in pb.authStore. The default LocalAuthStore uses LocalStorage when available and falls back to runtime memory otherwise, and it syncs auth state across browser tabs. AsyncAuthStore exists for third-party async storage, usually React Native.

How do I upload a file with pocketbase/js-sdk?

PocketBase accepts multipart/form-data, so you pass either a FormData instance or a plain object whose properties are File or Blob values. The plain-object form is converted to FormData behind the scenes.

Official sources

  1. License: MIT
  2. pocketbase/js-sdk on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pocketbase-js-sdk.svg)](https://hysenlabs.com/projects/pocketbase-js-sdk)