Minimal Next.js + @powersync/web app for testing parameterised sync streams
across local dev, a local production build, and a deployed build.
A thread page subscribes to the thread_runtime_data stream with
useSyncStream({ name, parameters: { thread_id }, ttl: 0 }) and re-subscribes
on every navigation (client/src/lib/powersync/hooks.ts). A second stream,
threads_list, is auto_subscribe: true and acts as the control. A diagnostics
panel on every page shows sdkVersion, connected, hasSynced, and the live
syncStreams list.
Auth runs in the browser via Supabase anonymous sign-in (see Auth).
Versions: @powersync/web@1.39.0, @powersync/react@1.10.0,
@journeyapps/wa-sqlite@1.7.2, PowerSync service 1.21.0.
backend/ Postgres + PowerSync service (docker compose), seeded with 3 threads
client/ Next.js 16 App Router client
cloud/ PowerSync Cloud config for the deployed setup (same streams)
Run everything locally, or point the client at a remote Supabase + PowerSync combo. Either way the client env vars are the same three below (see Auth).
Backend (local PowerSync at http://localhost:8080):
cd backend
docker compose upClient:
cd client
cp .env.local.template .env.local # then fill in the PowerSync + Supabase values
pnpm install
pnpm dev # local dev
pnpm build && pnpm start # local production buildUse a hosted PowerSync instance and Supabase project: set the env vars to their
public URLs and deploy client/, e.g. on Vercel with Root Directory = client.
Authentication runs entirely in the browser, so it works the same in all three
run modes. On first connect the client signs in anonymously with Supabase
(supabase.auth.signInAnonymously()) and returns the Supabase-issued JWT to
PowerSync from fetchCredentials (client/src/lib/powersync/connector.ts).
There is no app-minted token and no shared signing secret.
Required client env vars (all NEXT_PUBLIC_, so they reach the browser):
| Env var | What |
|---|---|
NEXT_PUBLIC_POWERSYNC_URL |
PowerSync endpoint the browser connects to |
NEXT_PUBLIC_SUPABASE_URL |
Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Supabase anon / publishable key (safe to expose) |
Two things must be set up outside the client:
- Enable anonymous sign-ins in Supabase (Auth → Providers → Anonymous).
- Configure PowerSync to verify Supabase JWTs (
backend/powersync.yaml): pointPS_SUPABASE_JWKS_URIat your project's JWKS endpoint and keepauthenticatedin the audience list (that is theaudSupabase puts on its tokens, anonymous users included).
Open a thread, navigate between threads, and hard-reload a thread page.
- Working: messages load and
syncStreamsliststhread_runtime_datawith the currentthread_idafter every navigation and after a reload. - Reproduced: the threads list populates (control stream works) but thread
pages show no messages and
thread_runtime_datanever appears insyncStreams. - Threads list empty or
connected: false: connection/auth problem with the setup, not the stream issue — checkNEXT_PUBLIC_POWERSYNC_URL, the Supabase env vars, and that the backend is configured to verify Supabase JWTs.
This reproduction was built with the assistance of AI (Claude). Manually reviewed and validated.