Evolu - React Hooks for Local-First Apps

React Hooks library for local-first apps (opens in a new tab) with end-to-end encrypted backup and sync using SQLite (opens in a new tab) and CRDT (opens in a new tab).

ℹ️

Evolu is designed for privacy, ease of use, and no vendor lock-in.

Local-first apps allow users to own their data. Evolu stores data in the user's device(s), so Evolu apps can work offline and without a specific server. Evolu Server

Evolu merges data changes made on different devices without conflicts using Conflict-free Replicated Data Type (CRDT). How Evolu Works

Getting Started · GitHub Repository (opens in a new tab) · Twitter (opens in a new tab)

Overview

import { pipe } from "@effect/data/Function";
import * as Schema from "@effect/schema/Schema";
import * as Evolu from "evolu";
 
const TodoId = Evolu.id("Todo");
type TodoId = Schema.To<typeof TodoId>;
 
const NonEmptyString50 = pipe(
  Schema.string,
  Schema.minLength(1),
  Schema.maxLength(50),
  Schema.brand("NonEmptyString50")
);
type NonEmptyString50 = Schema.To<typeof NonEmptyString50>;
 
const TodoTable = Schena.struct({
  id: TodoId,
  title: NonEmptyString50,
  description: Schema.nullable(Evolu.NonEmptyString1000),
  isCompleted: Evolu.SqliteBoolean,
});
type TodoTable = Schema.To<typeof TodoTable>;
 
const Database = Schema.struct({
  todo: TodoTable,
});
 
const { useQuery, useMutation } = Evolu.create(Database);
 
const { rows } = useQuery(
  (db) =>
    // A type-safe SQL query builder.
    db.selectFrom("todo").select(["id", "title"]).orderBy("createdAt"),
  // The filterMap helper for ad-hoc schema migrations.
  (row) => row
);
 
const { create, update } = useMutation();
 
if (!Schema.is(NonEmptyString50)(title)) return;
const { id } = create("todo", { title, isCompleted: false });
 
update("todo", { id, isCompleted: true }, onComplete);

Features

  • The official SQLite Wasm in all browsers (React Native and Electron soon)
  • E2E encrypted sync and backup with CRDT (merging changes without conflicts)
  • Free Evolu server for testing (paid production-ready soon, or you can run your own)
  • Typed database schema with branded types (NonEmptyString1000, PositiveInt)
  • Reactive queries with React Suspense support
  • Real-time experience via revalidation on focus and network recovery
  • Schema evolving via filterMap ad-hoc migration
  • No signup/login, no email collection, only Bitcoin-like mnemonic (12 words)

Community

The Evolu community is on GitHub Discussions (opens in a new tab). To chat with other community members, you can join the Evolu Discord (opens in a new tab).