Next.js
@atolljs/nextjs — the React hooks re-exported for App Router client components. The server-side surface — node:worker_threads pools inside route handlers via @atolljs/node — is documented under Backend → Next.js.
Install
npm install @atolljs/core @atolljs/nextjsClient components
Components calling the hooks carry the 'use client' directive — that boundary component is the edge; app/page.tsx can stay a server component that just renders it. Importing the connectWorker client is SSR-safe: the pool spawns lazily on the first method call, never during a server render, and field reads return undefined until the contract binds on the client.
'use client'; // required — the hooks read browser-side state
import { useSharedValue, useTask } from '@atolljs/nextjs';
import { counterMemory } from '../counter.memory';
import { counter } from '../counter'; // connectWorker client — safe to import under SSR
export function Counter() {
const count = useSharedValue(counterMemory, 'count');
const increment = useTask(counter.increment); // client method → latest-wins task
return (
<button onClick={() => increment.run(1)}>
count: {count ?? '…'}
</button>
);
}Binding API
| Export | Signature | What it does |
|---|---|---|
useObservable | useObservable(source: ObservableValue<T>): T | Subscribe to any observable snapshot (task or field). |
useSharedValue | useSharedValue(memory, key, select?, options?): T | undefined | Bind one shared-memory field to React state; optional selector + equality to slice updates. |
useTask | useTask(task | asyncFn): { data, pending, settled, elapsedMs, error, run, runOnce } | Bind an AsyncTask — or any async fn (e.g. a client method, wrapped via toTask) — to state and get its triggers. |
Deployment
- Next.js needs a Node runtime —
next start, a Node host, or a platform like Vercel. Static file hosts (GitHub Pages, S3) can't run it, which is why the Pages deploy mounts every other example but not this one. output: 'export'produces static HTML — client components still hydrate and client-side pools still spawn, but route handlers are dropped andnext.config.tsheaders()is not emitted. A shared-memory pool then needs the host (or a COI service worker, see Hosting & headers) to send COOP/COEP; a message-only pool needs neither.
Notes
- 'use client' is required on any component calling the hooks; app/page.tsx can stay a server component that just renders it.
- The connectWorker client is SSR-safe to import — its pool spawns lazily on the first method call, never during a server render.
- COOP/COEP in next.config.ts headers() is only needed when the pool uses sharedMemory; a message-only pool needs neither headers nor SharedArrayBuffer.