Introduction
This guide shows you how to add PowerSync to a Next.js app for local-first data and sync. You install the Web SDK, define a client-side schema, and connect sync so components query the local database instead of blocking on the network.PowerSync is tailored for client-side applications — there isn’t much benefit to using SSR with PowerSync. Some frameworks like Next.js push towards enabling SSR by default, which means code is evaluated in a Node.js runtime. The PowerSync Web SDK requires browser APIs which are not available in Node.js. For ergonomics, the SDK performs no-ops if used in Node.js (rather than throwing errors), but you should not expect any data from PowerSync during server-side rendering. If you are using SSR in your application, we recommend explicitly isolating PowerSync to client-side code.
Setup
Next.js Project Setup
Let’s start by bootstrapping a new Next.js application usingcreate-next-app.
Turbopack is supported in Next.js 16+. If you’re using an older version of Next.js, see the Webpack configuration (legacy) section below.
Install PowerSync Dependencies
Using PowerSync in a Next.js application will require the use of the PowerSync Web SDK and it’s peer dependencies. In addition to this we’ll also install@powersync/react, which provides several hooks and providers for easier integration.
This SDK currently requires @journeyapps/wa-sqlite as a peer dependency.
Copy Worker Assets
When using Turbopack, you need to copy the PowerSync worker files to your public directory. Add apostinstall script to your package.json:
package.json
public/@powersync/, which are required since Turbopack doesn’t support dynamic imports of workers yet.
Add
public/@powersync/* to your .gitignore file since these are generated assets.Next.js Config Setup
For Next.js 16+ with Turbopack, the configuration is minimal:next.config.ts
pnpm dev to start the development server and check that everything compiles correctly, before moving onto the next section.
Webpack Configuration (Legacy)
If you’re using an older version of Next.js (before 16) or prefer to use Webpack, use this configuration instead:next.config.ts
Configure a PowerSync Instance
Now that we’ve got our project setup, let’s create a new PowerSync Cloud instance and connect our client to it. For the purposes of this demo, we’ll be using Supabase as the backend source database that PowerSync will connect to. To set up a new PowerSync instance, follow the steps covered in the Installation - Database Connection docs page.Configure PowerSync in Your Project
Add Core PowerSync Files
Start by adding a new directory in./src/lib named powersync.
AppSchema
Create a new file called AppSchema.ts in the newly created powersync directory and add your App Schema to the file. Here is an example of this.
lib/powersync/AppSchema.ts
BackendConnector
Create a new file called BackendConnector.ts in the powersync directory and add the following to the file.
lib/powersync/BackendConnector.ts
fetchCredentials()- Used to return a JWT token to the PowerSync Service for authentication.uploadData()- Used to upload changes captured in the local SQLite database that need to be sent to the backend source database, in this case Supabase. We’ll get back to this further down.
.env file to our project which will contain two variables:
NEXT_PUBLIC_POWERSYNC_URL- This is the PowerSync instance url. You can grab this from the PowerSync Cloud dashboard.NEXT_PUBLIC_POWERSYNC_TOKEN- For development purposes we’ll be using a development token. To generate one, please follow the steps outlined in Development Token from our installation docs.
Create the PowerSync Provider
Add a new file at./src/lib/powersync/PowerSyncProvider.tsx. This is the client-side boundary that initializes the PowerSyncDatabase and exposes it via React Context.
lib/powersync/PowerSyncProvider.tsx
'use client' directive marks this as a Client Component — PowerSync requires browser APIs, so initialization must happen on the client. The lazy getDB() singleton ensures the database is only instantiated once (and only in the browser), which avoids duplicate connections when modules are re-evaluated during development.
The worker paths point to the pre-bundled workers copied to the public directory by the powersync-web copy-assets command. db.connect() is called with an instance of BackendConnector, which will validate the token returned from fetchCredentials and start syncing with the PowerSync Service.
Update layout.tsx
Update RootLayout to wrap children with the PowerSyncProvider. Importantly, the root layout should remain a Server Component — do not add 'use client' here. This is the standard Next.js App Router convention and is required if you want to export metadata (or use generateMetadata) from the layout. The client boundary is drawn at PowerSyncProvider, which is all that’s needed to get PowerSync running in the browser.
app/layout.tsx
Use PowerSync
Reading Data
In ourpage.tsx we can now use the useQuery hook or other PowerSync functions to read data from the SQLite database and render the results in our application.
app/page.tsx
Writing Data
Using theexecute function we can also write data into our local SQLite database.
uploadData in the BackendConnector class.