Quick Start
Install and run a minimal Live State server and client
1. Install
live-state is composed of a single package: @live-state/sync, but it's fully modular and tree-shakable, so you can keep only what you need.
Start off by installing the package:
npm install @live-state/sync2. Define your schema
Let's start by defining the schema. This is a declarative model of the data you want to store. This example will have a single collection: tasks.
import { createSchema, object, id, string, number } from "@live-state/sync";
const tasks = object("tasks", {
id: id(),
title: string(),
priority: number().default(0),
});
export const schema = createSchema({ tasks });3. Create a router
Now let's create a router. This will be a simple router, serving only a collection route for the tasks collection.
import { routeFactory, router } from "@live-state/sync/server";
import { schema } from "./schema";
export const appRouter = router({
schema,
routes: {
tasks: routeFactory().collectionRoute(schema.tasks),
},
});
export type Router = typeof appRouter; // Export the router type to use later in the client4. Create a server
Now that we have a router and schema, we can serve it. This example will use PostgreSQL for persistence and Express adapter.
import express from "express";
import expressWs from "express-ws";
import { Pool } from "pg";
import cors from "cors";
import { server, SQLStorage, routeFactory } from "@live-state/sync/server";
import { schema } from "./schema";
import { appRouter } from "./router";
const lsServer = server({
router: appRouter,
storage: new SQLStorage(
new Pool({
connectionString: "postgresql://admin:admin@localhost:5442/live-state",
})
),
schema,
});
const { app } = expressWs(express());
app
.use(express.urlencoded({ extended: true }))
.use(express.json())
.use(cors());
expressAdapter(app, lsServer);
app.listen(5001, () => console.log("api running on 5001"));4. Create a client
Last thing we need to do is create a client. For this example, we'll use the WebSocket client.
import {
createClient,
SubscriptionProvider,
useLiveQuery,
} from "@live-state/sync/client";
import { schema } from "./schema";
import type { Router } from "./router"; // Import only the router type, otherwise you will get build errors
export const { client, store } = createClient<Router>({
url: "ws://localhost:5001/ws",
schema,
storage: false,
});
store.mutate.tasks.insert({
id: "task_1",
title: "First task",
});
const tasks = store.query.tasks.get();That's it, now you can build UI and it will stay live-synced via WebSocket, with optimistic updates and conflict resolution built in. And as you can see, completely type-safe.