# Supabase Cache Helpers: SWR and React Query wrappers that know your schema

> This monorepo wraps the Supabase PostgREST, Storage and Realtime clients with SWR, React Query and a server-side caching layer, so cache keys and cache updates are derived from the query and the schema instead of being hand-written.

**psteinroe/supabase-cache-helpers** — A collection of framework specific Cache utilities for working with Supabase.

- Repository: https://github.com/psteinroe/supabase-cache-helpers
- Website: http://supabase-cache-helpers.com/
- Stars: 682 · Forks: 43
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/psteinroe-supabase-cache-helpers

## The gap the wrappers fill between SWR, React Query and Supabase

SWR and React Query both want a cache key, a fetcher and a list of things to refresh when data changes. Supabase hands you a query builder instead of a URL, and that mismatch is where the friction starts. Writing a stable key for a PostgREST query by hand means serialising the query builder output yourself, and refreshing the right entries after an insert means knowing which cached queries the new row could belong to.

supabase-cache-helpers takes that work on. The project describes itself as a collection of framework specific cache utilities, and its documentation states that the helpers parse any query into a unique and definite query key, then populate the cache with every mutation using implicit knowledge of the schema. That last part is the interesting promise: instead of invalidating a broad list of keys after a write, a mutation knows what it touched and can update the affected entries.

The audience is narrow and clear. If you are writing a React application on top of Supabase and have already adopted SWR or React Query, this removes a category of glue code. If you have not adopted either, the helpers do nothing for you, because the entire value is the integration with an existing cache manager.

## Five published packages and two shared cores

The monorepo publishes five packages meant for direct use. postgrest-swr and storage-swr wrap the PostgREST and Storage clients for SWR. postgrest-react-query and storage-react-query do the same for React Query. postgrest-server is a server-side caching wrapper for postgrest-js, which the project describes as a simple server-side abstraction to cache queries to the PostgREST API.

Two further packages are internal. postgrest-core holds the shared logic for postgrest-js and storage-core does the same for storage-js operations, and the README states plainly that they are not meant for direct usage. The shared-core split is what lets a SWR user and a React Query user get identical key generation and mutation behaviour, so a project that mixes both frameworks across pages does not end up with two incompatible cache conventions.

The repository is a pnpm workspace with a packages directory, a turbo.json for task orchestration, and a pnpm-workspace.yaml. Every package and app is written in TypeScript. A top-level tsconfig package holds the shared tsconfig.json files used throughout the monorepo, which is the piece that keeps the published type surfaces aligned between the core packages and the framework wrappers.

## Query keys are derived, so hand-written keys become unnecessary

The mechanism worth understanding is key derivation. Because the helper parses a query and turns it into a definite key, a component can fetch with a query builder and later write to the same table without the developer having to remember a key format. This is what makes pagination and infinite scroll queries practical, since the helpers list easy pagination and infinite scroll queries as features rather than leaving those to be solved per application.

The second mechanism is expansion. The README lists auto-expand mutation queries based on existing cache data to keep the app up to date. In practice this is the difference between a write that leaves a stale list on screen and a write that reconciles the cached rows with what the server now holds. The knowledge used for that comes from the schema, which is why the project ships a typegen recipe and why the type of your database is part of the setup rather than an afterthought.

Both mechanisms come with a cost that is easy to miss. Deriving keys means your cache layout is decided by the library rather than by your application, so you cannot pick a key that intentionally groups two different queries under one entry. Expanding a mutation into other queries means the helper writes into cache entries whose filters you never wrote. That is convenient in a small app and debatable in a large one.

## Mutations and realtime subscriptions write back into the same cache

The feature list names insert, update, upsert and delete mutations, and separately lists auto-populate cache after mutations and subscriptions. Subscriptions in this context come from the Realtime client, so a row changing in the database can flow back into a SWR or React Query cache without the component re-fetching on an interval or after a window focus.

Storage is treated with the same care. The project advertises a one-liner to upload, download and remove Supabase Storage objects, and storage-swr plus storage-react-query are the packages that provide it. The mechanism there is a wrapper around the Storage client rather than around PostgREST, but the cache-key and auto-population behaviour is shared through storage-core.

There is a subtlety about what all features of postgrest-js, storage-js and realtime-js are supported. The README states that the helpers support all features of those three client libraries, which is a promise about API surface coverage rather than about behaviour matching the clients exactly. If a helper decides to update the cache after a write, it may do so in a way the underlying client does not, and the underlying client keeps its own state in parallel. Anyone debugging a mismatch between what the client returns and what the UI shows needs to know that two sources of truth exist.

## Working in the monorepo with just, turbo and pnpm

There is no consumer install command in the README, so the documented path for users is the documentation site at psteinroe.github.io/supabase-cache-helpers, where the full examples live. For contributors, the repository root carries a justfile that wraps the underlying pnpm and turbo commands. The root package.json pins the package manager and states the runtime requirements in its engines field: node >=22.0.0 and pnpm 9, with pnpm@9.15.9 as the packageManager value.

The build recipe runs turbo across every package in the workspace:

```bash
build:
    pnpm turbo run build
```

There is a separate recipe that builds only the packages directory and excludes the examples, which is useful when you want the published output without the demo applications. The test recipe pins concurrency to one, which tells you the suites are not written to run in parallel:

```bash
test:
    pnpm turbo run test --concurrency=1
```

Other recipes cover lint and format through oxlint and oxfmt, type checking through turbo, and a clean target that removes build artifacts along with node_modules. Note that the example applications referenced by some recipes live under examples rather than packages, so filtering by the packages directory does not remove every consumer of the type definitions.

## Typegen writes database types into five places at once

The most operationally interesting recipe is typegen, because it shows how the schema knowledge the helpers rely on reaches the code. It runs the Supabase CLI against a local database and redirects the generated TypeScript types into several destinations, including the test folders of the published packages and the type folders of the example applications:

```bash
typegen:
    pnpm supabase gen types typescript --local > packages/postgrest-swr/tests/database.types.ts
    pnpm supabase gen types typescript --local > packages/postgrest-react-query/tests/database.types.ts
    pnpm supabase gen types typescript --local > packages/postgrest-core/tests/database.types.ts
    pnpm supabase gen types typescript --local > examples/swr/types/database.ts
    pnpm supabase gen types typescript --local > examples/react-query/types/database.ts
```

The --local flag means the types come from a database running on your own machine rather than from a hosted project, so this recipe assumes a working local Supabase setup. The repository includes a supabase directory, which is where such a local setup usually lives.

The duplicated output across five files is the cost side of the arrangement. A schema change means regenerating and committing types in several places, and the types must be in place before the auto-expansion behaviour can know which cached queries a mutation touches. If your workflow never runs this recipe, the helpers lose the schema knowledge that is their main advantage.

## Server-side caching covers PostgREST only, and releases are per package

postgrest-server is the odd package out. The others run in a browser, the server one runs wherever your server runs, and the README describes it as a server-side abstraction to cache queries to the PostgREST API. That is a narrower scope than the browser packages, and it is worth being precise about the difference. A server-side cache in front of PostgREST is a different tool from a client cache in front of a query builder: the first removes repeated round trips from a server, the second removes repeated round trips from a browser.

Release notes reinforce that this is a set of independently versioned packages rather than one product. Recent tags include @supabase-cache-helpers/postgrest-server@0.3.0 on 2026-01-21, and both @supabase-cache-helpers/storage-swr@1.1.6 and @supabase-cache-helpers/storage-react-query@1.3.6 on 2026-01-06. The storage wrappers are at different minor versions from the server package, so an upgrade is per package and the versions will not move in step. The repository manages this with changesets, and the root package.json carries ci:version and ci:version:rc scripts that bump versions and run the linter and formatter in one pass.

The licence is MIT, with a LICENSE file at the repository root. MIT places no obligation on downstream users beyond keeping the copyright notice and licence text, which makes it a low friction choice for closed source products. That is a licensing observation rather than advice about how to use it.

## Conclusion

supabase-cache-helpers fits teams already running Supabase with SWR or React Query who want cache keys, pagination and post-mutation cache updates to stop being hand-written strings. It does not fit projects on TanStack Query v5 style query key factories, apps whose schema knowledge is not available to the client, or teams that would rather own cache invalidation directly. Before adopting it, check the version of the wrapper package your framework uses, confirm that your schema types are generated the way the helpers expect, and read the package documentation linked from the project before mixing it with hand-written query keys.

## FAQ

### What does supabase-cache-helpers do that SWR or React Query do not?

The wrappers parse a query into a definite cache key and use knowledge of the schema to expand mutation queries and populate the cache after writes and realtime subscriptions.

### Which packages in supabase-cache-helpers should I install?

Install postgrest-swr or storage-swr for SWR, postgrest-react-query or storage-react-query for React Query, and postgrest-server for server-side caching of PostgREST queries.

### How do I generate the database types that supabase-cache-helpers uses?

The repository justfile has a typegen recipe that runs pnpm supabase gen types typescript --local against a local database and writes the output into the test folders of the packages and the examples.

### Do I need a local Supabase database to work on supabase-cache-helpers?

The typegen recipe uses the --local flag of the Supabase CLI, so it expects a database running on your own machine, and the repository includes a supabase directory for that setup.

## Sources

- [License: MIT](https://github.com/psteinroe/supabase-cache-helpers/blob/main/LICENSE)
- [Project website](http://supabase-cache-helpers.com/)
- [psteinroe/supabase-cache-helpers on GitHub](https://github.com/psteinroe/supabase-cache-helpers)
- [README](https://github.com/psteinroe/supabase-cache-helpers/blob/main/README.md)
- [Releases](https://github.com/psteinroe/supabase-cache-helpers/releases)

---

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