suspend-react review
suspend-react 0.1.3 is a module-level cache that connects promise-returning work to React Suspense. During render, `suspend` either returns a cached value or throws the pending promise; a rejected promise reaches an error boundary. Key arrays deduplicate work across the component tree. The package also exposes `preload`, `peek`, and `clear`, plus idle expiry and custom key equality. The current version only corrected package entry paths after 0.1.2 restored a missing README. It remains a low-level cache, with no query retries, mutations, hydration, status object, or request-scoped provider.
suspend-react 0.1.3 added 0.6 KB gzipped in our browser test and installed with no audit findings, but its cache is global and its last code push was in 2023. Use it for a narrow client-only resource with disciplined keys; pick TanStack Query or SWR for application server state.
We installed it
| Install | ✓ · 0.5s | 2 packages on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 0.6 KB | gzipped (1.2 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does suspend-react install cleanly?
Yes. In a fresh container with an empty cache, npm install suspend-react finished in 0.5s, leaving 2 packages and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does suspend-react add to a browser bundle?
0.6 KB gzipped (1.2 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does suspend-react work with both ESM and CommonJS?
Yes. Both import 'suspend-react' and require('suspend-react') worked in Node 22 in our run. The package is published as CommonJS.
Does suspend-react include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
suspend-react or @tanstack/react-query: which should you use?
@tanstack/react-query: Choose it for maintained server-state caching with retries, invalidation, cancellation, mutations, pagination, and hydration. suspend-react 0.1.3 added 0.6 KB gzipped in our browser test and installed with no audit findings, but its cache is global and its last code push was in 2023.
When should you not use suspend-react?
You need retries, cancellation, refetch intervals, stale data, mutations, optimistic updates, pagination, or network status. None is part of the four-export API.
Use it if
- A client-side React tree already uses Suspense and needs a small cache around one promise-returning resource.
- Render code should receive the resolved value directly while loading UI stays at a parent boundary.
- Your team can define stable, collision-safe key tuples and invalidate them after writes or logout.
- Preloading and synchronous peeking are useful, while a full query client would add unwanted policy and concepts.
- You need retries, cancellation, refetch intervals, stale data, mutations, optimistic updates, pagination, or network status. None is part of the four-export API.
- A long-lived server process renders several users. The README calls the cache global, with no request or provider boundary to prevent cross-request reuse.
- Cache keys cannot be centrally designed. Equal tuples collide across loaders unless you append a resource name or Symbol.
- Rejected work should retry automatically. The error stays in the entry and is thrown again until that key expires or `clear` removes it.
- You need maintenance tied to current React releases. Version 0.1.3 shipped in June 2023 and the repository's last push was October 2023.
Setup reality
We installed suspend-react 0.1.3 in a fresh, unprivileged Node 22 sandbox in 0.5 seconds. npm left 2 packages and 1 MB on disk. The package has 0 direct dependencies, one React peer dependency, and 32 KB unpacked. npm audit found 0 vulnerabilities at all severities. Our measurement setup used 3 CPUs, 8 GB of RAM, and no cache. CommonJS require() and ESM import both worked, and TypeScript declarations are bundled.
React is the one peer dependency, declared as version 17 or newer even though the README mentions Suspense support from React 16.6. The package is CommonJS and has no exports map. Our browser build measured 1.2 KB minified and 0.6 KB gzipped. Every suspending component needs an ancestor <Suspense> fallback; promise failures need a separate error boundary because Suspense only handles waiting.
Keys are compared item by item with === unless equal is supplied. Fresh object literals therefore miss the cache, while a generic key such as [42] can collide with another loader. Append a stable resource string or Symbol. The loader receives all key items as arguments, including that suffix. A lifespan of 0 keeps an entry forever, and each read restarts a positive idle timer.
preload starts the same entry and returns undefined; peek returns a resolved value or undefined without throwing. A rejected promise remains cached. Clear the exact tuple before a retry and clear user-specific entries during logout and tests. There is no AbortSignal support, server dehydration, cache provider, or unmount cleanup. Server rendering needs isolation outside this 0.1.3 module, which is usually reason enough to choose a query library instead.
Patterns
Read data through Suspense suspend-fetch
import { suspend } from 'suspend-react';
function User({ id }) {
const user = suspend(fetchUser, [id, 'user']);
return <strong>{user.name}</strong>;
}The loader receives both key items. The string suffix separates this entry from another resource keyed by the same id.
Provide pending UI add-suspense-boundary
import { Suspense } from 'react';
<Suspense fallback={<p>Loading user...</p>}>
<User id={42} />
</Suspense>suspend throws the pending promise during render, so an ancestor Suspense boundary must provide the fallback.
Warm an entry before render preload-resource
import { preload } from 'suspend-react';
preload(fetchUser, [42, 'user']);preload returns undefined and shares the exact key with a later suspend call.
Read only a resolved entry peek-cache
import { peek } from 'suspend-react';
const cached = peek([42, 'user']);
if (cached) console.log(cached.name);peek does not suspend. It returns undefined for missing and still-pending entries.
Invalidate one resource clear-one-entry
import { clear } from 'suspend-react';
await updateUser(42, changes);
clear([42, 'user']);The tuple must match the original key by the configured equality rule before the next render can load fresh data.
Reset the global cache clear-all-entries
import { clear } from 'suspend-react';
clear();With no key, clear removes every module-level entry. This is useful between tests but broad for a running app.
Expire an idle cache value expire-idle-entry
const user = suspend(fetchUser, [id, 'user'], {
lifespan: 60_000,
});The 60-second timer restarts on reads; `lifespan: 0` keeps the entry indefinitely.
Give a library resource a unique key use-symbol-key
const userResource = Symbol('user-resource');
export function User({ id }) {
const user = suspend(fetchUser, [id, userResource]);
return <span>{user.name}</span>;
}A Symbol prevents another package from colliding with the same numeric id and text suffix.
Compare object keys by value compare-structured-key
import equal from 'fast-deep-equal';
const result = suspend(runSearch, [{ query, page }], { equal });Default equality is `===`; a new object would otherwise create a new entry on each render. fast-deep-equal is a separate dependency.
Clear a failed entry before retry retry-after-error
function retryUser(id) {
clear([id, 'user']);
startTransition(() => setAttempt((n) => n + 1));
}A rejection is stored on the cache entry and thrown again until that exact key is cleared or expires.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| @tanstack/react-query | npm | Choose it for maintained server-state caching with retries, invalidation, cancellation, mutations, pagination, and hydration. |
| swr | npm | Choose it for hook-based stale-while-revalidate fetching, focus refresh, mutation, and status values. |
| use-async-resource | npm | Choose it for another Suspense-oriented async resource abstraction with reader and lazy-resource APIs. |
More web frontend guides
postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

