API reference@evolu/commonlocal‑first/Evolu › EvoluConfig

Defined in: packages/common/src/local-first/Evolu.ts:97

Configuration for createEvolu.

Properties

appName

readonly appName: string & Brand<"UrlSafeString"> & Brand<"AppName">;

Defined in: packages/common/src/local-first/Evolu.ts:128

An application name used in logs and local database names.

Evolu combines appName with the AppOwner identity to identify the local database. Changing either opens a different database. Keep appName stable across ordinary application updates.

Instances that share an appName and AppOwner open the same database and must use the same schema. Evolu applies the schema of the first instance and later instances join it.

A different app name lets you create a separate local replica for the same AppOwner—for example, to test a different SQLite implementation or index configuration, or rebuild a replica for debugging while preserving the existing database.

Evolu supports running these databases concurrently. Their local separation does not isolate synchronization: replicas synchronizing the same owners through the same relay can still exchange changes. Changing appName neither migrates existing local data nor isolates incompatible schemas.

Example

import { AppName, assertEqual } from "@evolu/common";

const appName = AppName.orThrow("MyApp");
assertEqual(appName, "MyApp");

appOwner

readonly appOwner: AppOwner;

Defined in: packages/common/src/local-first/Evolu.ts:151

AppOwner used to create this Evolu instance.

Exposed as Evolu.appOwner. Create an AppOwner before the first run, or restore one from secure storage before creating Evolu.

AppOwner controls access to the encrypted local SQLite database. If its secret material (Owner secret / Mnemonic) is not stored safely, data written by that instance is permanently inaccessible.

Best onboarding UX is accountless first use: create an AppOwner, let users try a ready-to-use app, then prompt backup of evolu.appOwner.

Recommended usage:

  • Create and persist an appOwner for first run, then guide the user to back it up after user activity.
  • Pass appOwner restored from secure storage (for example, Expo SecureStore, WebAuthn-backed storage, or app-managed account recovery flow).

indexes?

readonly optional indexes?: IndexesConfig;

Defined in: packages/common/src/local-first/Evolu.ts:202

Use the indexes option to define SQLite indexes.

Table and column names are not typed because Kysely doesn't support it.

https://medium.com/@JasonWyatt/squeezing-performance-from-sqlite-indexes-indexes-c4e175f3c346

Example

import { createEvolu, id, testAppName, testAppOwner } from "@evolu/common";

const Schema = {
  todo: { id: id("Todo") },
  todoCategory: { id: id("TodoCategory") },
};

const _createTodoEvolu = createEvolu(Schema, {
  appName: testAppName,
  appOwner: testAppOwner,
  transports: [],
  indexes: (create) => [
    create("todoCreatedAt").on("todo").column("createdAt"),
    create("todoCategoryCreatedAt").on("todoCategory").column("createdAt"),
  ],
});

memoryOnly?

readonly optional memoryOnly?: boolean;

Defined in: packages/common/src/local-first/Evolu.ts:165

Keep the database in memory instead of persisting it on this device.

This option controls device persistence independently of synchronization. When synchronization is enabled, data can still be synchronized and persisted remotely.

Useful for testing or temporary sessions. Data that exists only in this database is lost when the database closes.

The default value is: false.


onDatabaseDeleted?

readonly optional onDatabaseDeleted?: () => void;

Defined in: packages/common/src/local-first/Evolu.ts:210

Called when this instance's local database is deleted.

Apps can use this to update UI immediately because the corresponding Evolu instance becomes unusable after local database deletion.

onOwnerDeleted?

readonly optional onOwnerDeleted?: (owner: Owner) => void;

Defined in: packages/common/src/local-first/Evolu.ts:218

Called when local data for an Owner is deleted.

Apps can use this to update UI immediately because that owner stops being used across tabs and instances.

transports?

readonly optional transports?: readonly OwnerWebSocketTransport[];

Defined in: packages/common/src/local-first/Evolu.ts:292

Transport configuration for sync and backup.

If not specified, Evolu uses the default Evolu relay. Pass one or more transports to override it with your own relays. Pass an empty array to disable sync, which is useful when sync should be configured later.

Empty transports start the instance without sync. In that case, Evolu.useOwner must be called with explicit non-empty transports to enable sync for any Owner, including the AppOwner.

Redundancy: The ideal setup uses at least two completely independent relays - for example, a home relay and a geographically separate relay. Data is sent to both relays simultaneously, providing true redundancy similar to using two independent clouds. This eliminates vendor lock-in and ensures your app continues working regardless of circumstances - whether home relay hardware fails or disappears, or a remote relay provider shuts down.

Currently supports:

  • WebSocket: Real-time bidirectional communication with relay servers

Use createOwnerWebSocketTransport to create WebSocket transport configurations with proper URL formatting and OwnerId inclusion. The OwnerId in the URL enables relay authentication, allowing relay servers to control access (e.g., for paid tiers or private instances).

The default value is:

[{ type: "WebSocket", url: "wss://free.evoluhq.com" }].

Example

import {
  assertEqual,
  createOwnerWebSocketTransport,
  testAppOwner,
  type OwnerTransport,
} from "@evolu/common";

// Use one relay.
const _singleRelay = [
  { type: "WebSocket", url: "wss://relay1.example.com" },
] satisfies ReadonlyArray<OwnerTransport>;

// Use independent relays for redundancy.
const _redundantRelays = [
  { type: "WebSocket", url: "wss://relay1.example.com" },
  { type: "WebSocket", url: "wss://relay2.example.com" },
] satisfies ReadonlyArray<OwnerTransport>;

// Start local-only before authentication. After authentication, pass an
// owner-scoped transport to evolu.useOwner.
const _localOnlyBeforeAuthentication =
  [] satisfies ReadonlyArray<OwnerTransport>;

// Include the OwnerId when the relay authenticates owners.
const authenticatedRelay = [
  createOwnerWebSocketTransport({
    url: "wss://relay.example.com",
    ownerId: testAppOwner.id,
  }),
];

assertEqual(
  authenticatedRelay[0]?.url,
  `wss://relay.example.com?ownerId=${testAppOwner.id}`,
);