Skip to main content

Quickstart

Let's dive in and start developing with ElectricSQL. First, we'll get the stack setup, then we'll show you the basics of using the system.

note

If you'd prefer to understand a bit more about the system before jumping into code, start with the Introduction instead.

Setup

Get setup quickly using the create-electric-app starter template. Or install, run and integrate the components yourself.

Make sure you have Docker and Node.js (>=16.11) and then:

npx create-electric-app@latest my-app --template react

You can specify the desired template, available options are react, vue, expo, and react-native. Change directory into my-app and start the backend services. This will use Docker Compose to run Postgres and the Electric sync service:

cd my-app
npx electric-sql start --with-postgres
# Aliased in package.json as `npm run backend:start`

Open another terminal tab, navigate back to the my-app directory and create the database schema (defined in ./db/migrations):

npm run db:migrate

Generate your type-safe database client:

npx electric-sql generate
# Aliased in package.json as `npm run client:generate`

Start your app:

npm run dev

Open localhost:5173 in your web browser. That's it, you're up and running :)

Usage

The next section goes over the basics of using ElectricSQL. It's a quick summary of the information you'll find in more detail in the Usage guide.

Define your schema

ElectricSQL works on top of Postgres. You define and evolve the Postgres database schema using your normal migrations tooling.

The starter template has set you up with a simple data model defined in ./db/migrations. To evolve the schema you can add additional files and run npm run db:migrate again, e.g.:

echo '
CREATE TABLE accounts (
id UUID PRIMARY KEY,
email TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);

ALTER TABLE accounts ENABLE ELECTRIC;
' > db/migrations/02-create_foo_table.sql

npm run db:migrate

See Usage -> Data modelling -> Migrations and Integrations -> Backend for more information.

Expose data

Expose data using DDLX rules. First, electrify each table you'd like to sync:

ALTER TABLE items
ENABLE ELECTRIC;

Then assign roles and access permissions:

ELECTRIC GRANT ALL
ON items
TO ANYONE;

Instantiate

Wrap your SQLite driver with a type-safe, schema-aware database Client:

import { electrify, ElectricDatabase } from 'electric-sql/wa-sqlite'
import { schema } from './generated/client'

const config = {
url: "http://localhost:5133"
}
const conn = await ElectricDatabase.init('my.db')
const electric = await electrify(conn, schema, config)

Connect and authenticate

Connect to Electric and authenticate the local app with the replication protocol using a JSON Web Token:

await electric.connect('<your JWT>')

Sync data

Sync data into the local database using Shapes:

const db = electric.db
const shape = await db.items.sync({
where: {
// ... clauses
},
include: {
// ... relations
}
})

Read data

Bind live data to your components using Live queries:

const { results } = useLiveQuery(
db.items.liveMany({
where: {
// ... filter
},
select: {
// ... columns
},
orderBy: {
// ... sort
},
take: 20
})
)

Either using the Prisma-inspired client or if you prefer just raw SQL:

const { results } = useLiveQuery(
db.liveRawQuery({
sql: 'SELECT * FROM items where foo = ?',
args: ['bar']
})
)

Write data

Write data directly to the local database using Local writes:

const item = await db.items.create({
data: {
// ... item data
}
})

Writes automatically cause any relevant live queries to update. For example, if you take the following component:

import { genUUID } from 'electric-sql/util'

const MyComponent = () => {
const { db } = useElectric()!
const { results } = useLiveQuery(
db.items.liveMany()
)

const add = async () => (
await db.items.create({
data: {
value: genUUID()
}
})
)

return <List items={results} add={add} />
}

Calling add will insert a new item into the local database. ElectricSQL will automatically detect and replicate the write. The replication process emits a notification, causing the live query to re-run. This updates the value of the results state variable, which triggers the component to re-render.

This automatic reactivity works no matter where the write is made locally, on another device, by another user, or directly into Postgres.

Next steps

Take a look at the Examples, see the Usage and Integrations guides and the API docs.

You can also join the Discord community and star us on GitHub.