# Get started with local-first

This guide will help you get started with the Evolu local-first platform.

> Requirements: `TypeScript 5.7` or later with the `strict` and
> `exactOptionalPropertyTypes` flags enabled in `tsconfig.json` file.

## Installation

Evolu offers SDKs for a variety of frameworks, including React, Svelte, React Native, Expo, and others. Below, you can see how to install the SDKs for each framework.

## Define schema

First, define your app database schema—tables, columns, and types.

Evolu uses [Type](https://evolu.dev/docs/api-reference/common/Type) for data modeling. Instead of plain JS types like string or number, we recommend using branded types to enforce domain rules.

```ts

// Primary keys are branded types, preventing accidental use of IDs across
// different tables (e.g., a TodoId can't be used where a UserId is expected).
const TodoId = Evolu.id("Todo");
type TodoId = typeof TodoId.Type;

// Schema defines database structure with runtime validation.
// Column types validate data on insert/update/upsert.
const Schema = {
  todo: {
    id: TodoId,
    // Branded type ensuring titles are non-empty and ≤100 chars.
    title: Evolu.NonEmptyString100,
    // SQLite doesn't support the boolean type; it uses 0 and 1 instead.
    isCompleted: Evolu.nullOr(Evolu.SqliteBoolean),
  },
};
```

> Evolu automatically adds [system
> columns](https://evolu.dev/docs/api-reference/common/local-first/variables/SystemColumns-1):
> `createdAt`, `updatedAt`, `isDeleted`, and `ownerId`.

## Create Evolu

After defining the schema, create an Evolu instance for your environment.

// Create a typed React Hook returning an instance of Evolu
const useEvolu = createUseEvolu(evolu);

// Use the Hook in your app
const { insert, update } = useEvolu();
```

```ts {{ title: 'React Native', language: 'tsx' }}

const evolu = createEvolu(evoluReactNativeDeps)(Schema, {
 appName: Name.orThrow("your-app-name"),
 transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com
});

// Wrap your app with 

// Create a typed React Hook returning an instance of Evolu
const useEvolu = createUseEvolu(evolu);

// Use the Hook in your app
const { insert, update } = useEvolu();
```

```ts {{ title: 'Expo', language: 'tsx' }}

const evolu = createEvolu(evoluReactNativeDeps)(Schema, {
 appName: Name.orThrow("your-app-name"),
 transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com
});

// Wrap your app with 

// Create a typed React Hook returning an instance of Evolu
const useEvolu = createUseEvolu(evolu);

// Use the Hook in your app
const { insert, update } = useEvolu();
```

```ts {{ title: 'Svelte'}}

const evolu = Evolu.createEvolu(evoluSvelteDeps)(Schema, {
  appName: Evolu.Name.orThrow("your-app-name"),
  transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com
});
```

```ts {{ title: 'Vue', language: 'ts' }}

const evolu = createEvolu(evoluWebDeps)(Schema, {
  appName: Name.orThrow("your-app-name"),
  transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com
});

export default defineComponent({
  setup() {
    provideEvolu(evolu);
    const { insert, update } = evolu;
    return { insert, update };
  },
});
```

```ts {{ title: 'Vanilla JS' }}

const evolu = createEvolu(evoluWebDeps)(Schema, {
  appName: Name.orThrow("your-app-name"),
  transports: [{ type: "WebSocket", url: "wss://your-sync-url" }], // optional, defaults to free.evoluhq.com
});
```

</SinglePlatformCodeGroup>

## Mutate data

## Query data

Evolu uses type-safe TypeScript SQL query builder [Kysely](https://github.com/koskimas/kysely), so autocompletion works out-of-the-box.

Let's start with a simple `Query`.

```ts
const allTodos = evolu.createQuery((db) => db.selectFrom("todo").selectAll());
```

Once we have a query, we can load or subscribe to it.

## Delete data

To delete a row, set `isDeleted` to `sqliteTrue` (1). Evolu uses **soft deletes** instead of permanent deletion.

When querying, filter out deleted rows:

```ts
const activeTodos = evolu.createQuery((db) =>
  db
    .selectFrom("todo")
    .selectAll()
    // Filter out deleted rows
    .where("isDeleted", "is not", Evolu.sqliteTrue)
    .orderBy("createdAt"),
);
```

## Protect data

**Privacy is essential for Evolu**, so all data are **encrypted** with an encryption key derived from a cryptographically strong secret (which can be represented as a [mnemonic](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)) or provided by an external hardware device.

## Purge data

To clear all local data from the device (this is different from soft deletes):

```ts
evolu.resetAppOwner();
```

> This removes all data from the local database. This is not a soft delete—it's
> a complete reset.

## Restore data

To restore synced data on any device:

```ts
evolu.restoreAppOwner(mnemonic);
```

To learn more about Evolu, explore our [playgrounds](https://evolu.dev/docs/playgrounds) and [examples](https://evolu.dev/docs/examples).