Skip to main content
This guide shows you how to set up PowerSync with Neon and run a React notes demo app. The app reads and writes a local SQLite database, so it responds instantly and keeps working without a network connection. The demo app is a fork of Neon’s Data API and Neon Auth demo with PowerSync added.
Comparing PowerSync with Neon Realtime? See PowerSync vs Neon Realtime.
Before you start, make sure you have:

Architecture

Diagram of the PowerSync Service syncing data from Neon Postgres to SQLite in the app, and the app uploading writes to Neon through the Neon TypeScript SDK

Neon + PowerSync architecture

The PowerSync Service replicates data from Neon Postgres and syncs it to each client’s SQLite database, based on your Sync Streams. When the app writes to SQLite, the PowerSync SDK also adds the change to an upload queue. While the device is online, the SDK calls the app’s uploadData() function, which sends queued changes to Neon through the Neon Data API. Neon Auth handles sign-in. The Data API and PowerSync both accept the JWTs that Neon Auth issues. For more on how PowerSync works, see the Architecture Overview.

Overview

1

Configure Neon

  • Create a Neon project with Neon Auth and the Data API
  • Enable logical replication
  • Create the demo database schema
  • Create the PowerSync database user and publication
2

Configure PowerSync

  • Connect PowerSync to Neon
  • Configure Neon Auth
  • Configure Sync Streams
3

Run the Demo App

Configure and run the notes demo app, then test sync.

Configure Neon

Create a Neon Project

Create a project with Neon Auth, Neon’s managed Better Auth service, and the Data API.
  1. In the Neon Console, create a project.
  2. Enable Better Auth.
  3. Enable the Data API under Postgres database > Data API. Keep Use Neon Auth selected and select Grant public schema access, which is off by default.
The demo app uploads writes through the Data API as the authenticated role. Grant public schema access (--add-default-grants in the CLI) gives this role read and write access to tables in the public schema, including tables you create later. Without these grants, the demo app’s uploads fail.

Enable Logical Replication

PowerSync uses Postgres logical replication to read changes from your database. Enabling logical replication can’t be undone. It also restarts your project’s computes, which drops active connections.
In the Neon Console, go to Settings > Postgres and enable Logical Replication.
While PowerSync is connected, its replication connection keeps your Neon compute active, so the compute doesn’t scale to zero. This uses compute hours continuously, which counts toward your Neon plan’s limits.

Create the Demo Database Schema

The demo app uses Drizzle migrations to create its tables and Row Level Security (RLS) policies.
  1. Clone the demo app and install its dependencies:
  2. Get a direct connection string:
    • Web UI: In the Neon Console, click Connect, turn off Connection pooling, and copy the connection string.
    • CLI: Run neon connection-string --project-id <project-id>. It returns a direct connection string by default.
  3. Create a .env file in the demo directory and add the connection string:
  4. Run the migration:
The migration creates these tables:
The RLS policies let each signed-in user read and write their own notes and paragraphs, and read shared notes and their paragraphs.

Create a PowerSync Database User

Run the following SQL in the Neon Console under Postgres database > SQL Editor, or with psql "$(neon connection-string --project-id <project-id>)". The role needs BYPASSRLS so that PowerSync can replicate every row of the RLS-protected demo tables. Your Sync Streams then decide which rows each user receives.
To restrict read access to specific tables, explicitly list allowed tables for both the SELECT privilege, and for the publication mentioned in the next step (as well as for any other publications that may exist).

Create the Postgres Publication

Run the following SQL in the SQL Editor or with psql:
Note that the PowerSync Service has to read all updates present in the publication, regardless of whether the table is referenced in your Sync Streams. This can cause large spikes in memory usage or introduce replication delays, so if you’re dealing with large data volumes, you’ll want to specify a comma-separated subset of tables to replicate instead of FOR ALL TABLES.
The snippet above replicates all tables and is the simplest way to get started in a dev environment.

Configure PowerSync

Create a PowerSync Cloud Instance

When creating a project in the PowerSync Dashboard, Development and Production instances of the PowerSync Service will be created by default. Select the instance you want to configure.If you need to create a new instance, follow the steps below.
  1. In the dashboard, select your project and open the instance selection dropdown. Click Add Instance.
  1. Give your instance a name, such as “Production”.
  2. [Optional] You can change the default cloud region. You can’t change the region after you create the instance. See Regions for details.
  3. Click Create Instance.

Connect PowerSync to Neon

  1. In the Neon Console, click Connect, turn off Connection pooling, and copy the connection string.
  2. In the PowerSync Dashboard, select your project and instance and go to the Database Connection view.
  3. Select the Postgres tab.
  4. Paste the connection string into the URI field. PowerSync fills in the other connection fields from the URI.
  5. Change Username and Password to the powersync_role and password you created in Create a PowerSync Database User.
  6. Keep SSL Mode set to verify-full. PowerSync trusts Neon’s certificate by default, so you don’t need to add a server certificate.
  7. Click Test Connection and fix any errors.
  8. Click Save Connection.
PowerSync now creates an isolated cloud environment for your instance. This typically takes a minute or two.

Configure Neon Auth

The demo app sends PowerSync the JWT that Neon Auth issues for the signed-in user. To verify these JWTs, PowerSync needs two values from Neon:
  • JWKS URL: The public keys that Neon Auth publishes as a JSON Web Key Set (JWKS), for example https://ep-cool-darkness-123456.neonauth.c-2.us-east-2.aws.neon.tech/neondb/auth/.well-known/jwks.json.
  • JWT audience: The origin of your Neon Auth URL, which is the URL without the path and without a trailing /, for example https://ep-cool-darkness-123456.neonauth.c-2.us-east-2.aws.neon.tech. PowerSync rejects a token if its aud value doesn’t match exactly.
You also enable development tokens, which you use to test your Sync Streams at the end of this guide.
Find the Auth URL and JWKS URL in the Neon Console under Settings > Better Auth. Then, in the PowerSync Dashboard, go to the Client Auth view and set the following fields:
  • Development tokens: Enable this setting.
  • JWKS URI: Enter the JWKS URL from Neon.
  • JWT Audience: Enter the origin of the Auth URL from Neon.
Then click Save and Deploy.

Configure Sync Streams

Sync Streams define which data syncs to which users’ devices. In the demo app, each user syncs their own notes and paragraphs, plus all shared notes and their paragraphs. Use the following Sync Config:
  1. In the PowerSync Dashboard, go to the Sync Streams view.
  2. Replace the contents of the editor with the Sync Config above.
  3. Click Validate and fix any errors.
  4. Click Deploy.

Run the Demo App

Configure Environment Variables

Add the following variables to the .env file in the demo directory:
If you use the CLI, neon data-api get --project-id <project-id> --database neondb prints the Data API URL, and neon neon-auth status --project-id <project-id> prints the Auth URL as base_url. Your PowerSync instance URL is https://<instance-id>.powersync.journeyapps.com, where <instance-id> is the instance_id value in powersync/cli.yaml.

Start the App

Start the development server:
Open http://localhost:5173 and sign up. Neon Auth accepts requests from localhost while Allow Localhost is on, which is the default. If you deploy the app, add its domain in the Neon Console under Settings > Better Auth > Domains. The notes list is empty at first. Create a note, then disconnect your device from the network (for example, turn off Wi-Fi) and edit the note. When you reconnect, the SDK uploads the queued changes, and they appear in the notes and paragraphs tables in Neon.
Demo app showing a list of two notes for the signed-in user

The demo app after creating two notes

If a note disappears shortly after you create it, the Data API rejected the upload with a permission error (42501), and the demo app discarded the change. To grant access to the demo tables, run GRANT SELECT, INSERT, UPDATE, DELETE ON notes, paragraphs TO authenticated; in the SQL Editor.

Test Your Sync Streams (Optional)

To see which data syncs to a specific user, generate a development token for a user who signed up in the demo app, and open it in the Sync Diagnostics Client. Use the user’s ID as the token subject. This ID is the owner_id value of the user’s notes.
In the PowerSync Dashboard, go to the Sync Test view. Enter the user ID as the token subject, then click Generate token and Launch Sync Diagnostics Client.
If you run into problems, ask us on Discord.