Skip to content

Why fetch when

you can sync?

Swap out your queries, data fetching and caching for bulletproof sync.

Sync your Postgres data wherever you need it

Electric syncs little subsets of your Postgres data into local apps and services. So you can have the data you need, in-sync, wherever you need it.

Makes manual data fetching obsolete

Why build APIs and write code to fetch data over the network when you can just sync instead?

Use cases diagrammeUse cases diagramme

Demo apps

See the kind of applications you can build with Electric and what they feel like to use.

Linearlite

Local-first project management app built with Electric and PGlite.

Notes

Collaborative note-taking app with sync powered by Electric and Yjs.

Pixel art

Collaborative pixel art editor with real-time multiplayer editing.

Solves the hard problems, so you don't have to

Electric solves data loading, cache invalidation, scaling and availability.

Get started now

You can start by adopting Electric incrementally, one data fetch at a time.

tsx
import { useShape } from '@electric-sql/react'

const Component = () => {
  const { data } = useShape({
    url: `${BASE_URL}/v1/shape`,
    params: {
      table: `items`
    }
  })

  return (
    <pre>{ JSON.stringify(data) }<pre>
  )
}

And you can level-up to syncing into a local embedded PGlite database.

tsx
import { PGlite } from '@electric-sql/pglite'
import { live } from '@electric-sql/pglite/live'
import { electricSync } from '@electric-sql/pglite-sync'
import { useLiveQuery } from '@electric-sql/pglite-react'

// Create a persistent local PGlite database
const pg = await PGlite.create({
  dataDir: 'idb://my-database',
  extensions: {
    electric: electricSync(),
    live
  }
})

// Setup the local database schema
await pg.exec(`
  CREATE TABLE IF NOT EXISTS items (
    id SERIAL PRIMARY KEY,
  );
`)

// Establish a persistent shape subscription
await pg.electric.syncShapeToTable({
  shape: { url: `${BASE_URL}/v1/shape` },
  table: 'items',
  primaryKey: ['id'],
})

// Bind data to your components using live queries
// against the local embedded database
const Component = () => {
  const items = useLiveQuery(
    `SELECT * FROM items;`
  )

  return <pre>{JSON.stringify(items)}</pre>
}