mrkeyoor.com_
Wed 23 Sept 00:33 UTC
npmWeb Frontendupdated 22 Sept 2026

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.

Verdict

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

Lab card: what happened when we installed suspend-reactScreenshot of suspend-react documentation
Install✓ · 0.5s2 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browser0.6 KBgzipped (1.2 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 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.

API stability3/5Version 0.1.3 has only four exports: `suspend`, `preload`, `peek`, and `clear`. The key tuple, optional `lifespan`, and optional equality callback make the behavior inspectable. Yet the package is still below 1.0, its README anticipates future React cache-boundary work, and the claimed React 16.6 compatibility differs from the published `react >=17` peer range. Keep calls behind a small application wrapper if replacement must remain possible.
Docs3/5The README explains thrown promises, Suspense fallbacks, error boundaries, cache tuples, idle lifespan, reference equality, preloading, peeking, clearing, global-key collisions, and TypeScript inference with compact examples. It does not cover request isolation for SSR, cached-error retries, cancellation, unmount behavior, or newer React server patterns. The note about prospective React 18 caching still reads as future work despite the package's 2023 release date.
Maintenance2/5npm published 0.1.3 on June 13, 2023 to repair package entry paths, and GitHub records the last push on October 24, 2023. The repository is unarchived, has 1,410 stars, and reports 13 open issues and pull requests. A 1.2 KB cache can remain usable without frequent releases, but React rendering and cache APIs keep moving, and there is no recent release evidence that this integration has followed them.
Ecosystem3/5npm counted 4,915,787 downloads in the latest week, and the package belongs to pmndrs, works through CommonJS and ESM consumers, bundles TypeScript types, and depends only on the React peer. The surrounding integration surface is sparse: no devtools, persistence, mutation helpers, hydration format, adapters, or provider-scoped cache. Popularity likely includes transitive use, while direct application needs often exceed its four functions.

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.
Skip it if

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

PackageRegistryPick it when
@tanstack/react-querynpmChoose it for maintained server-state caching with retries, invalidation, cancellation, mutations, pagination, and hydration.
swrnpmChoose it for hook-based stale-while-revalidate fetching, focus refresh, mutation, and status values.
use-async-resourcenpmChoose 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.