[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [local‑first/Evolu](https://evolu.dev/docs/api-reference/common/local-first/Evolu) › EvoluConfig

Defined in: [packages/common/src/local-first/Evolu.ts:85](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/local-first/Evolu.ts#L85)

## Properties

<a id="appname"></a>

### appName

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

Defined in: [packages/common/src/local-first/Evolu.ts:106](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/local-first/Evolu.ts#L106)

The app name. Evolu is multitenant - it can run multiple instances
concurrently. The same app can have multiple instances for different
accounts.

Evolu derives the final instance name from `appName` and `appOwner` in
[EvoluConfig](https://evolu.dev/docs/api-reference/common/local-first/Evolu/interfaces/EvoluConfig). The derived instance name is used as the SQLite
database filename and as the log prefix. This ensures that each
[Owner](https://evolu.dev/docs/api-reference/common/local-first/Owner/interfaces/Owner) gets a separate local database while preserving a readable app
prefix.

### Example

```ts

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

---

<a id="appowner"></a>

### appOwner

```ts
readonly appOwner: AppOwner;
```

Defined in: [packages/common/src/local-first/Evolu.ts:129](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/local-first/Evolu.ts#L129)

[AppOwner](https://evolu.dev/docs/api-reference/common/local-first/Owner/interfaces/AppOwner) used to create this [Evolu](https://evolu.dev/docs/api-reference/common/local-first/Evolu/interfaces/Evolu) instance.

Exposed as [Evolu.appOwner](https://evolu.dev/docs/api-reference/common/local-first/Evolu/interfaces/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).

---

<a id="indexes"></a>

### indexes?

```ts
readonly optional indexes?: IndexesConfig;
```

Defined in: [packages/common/src/local-first/Evolu.ts:268](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/local-first/Evolu.ts#L268)

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

```ts
import {
  AppName,
  assertTrue,
  createAppOwner,
  createEvolu,
  createOwnerSecret,
  createRandomBytes,
  id,
} from "@evolu/common";

const Schema = {
  todo: { id: id("Todo") },
  todoCategory: { id: id("TodoCategory") },
};
// Create once, persist the mnemonic securely, and restore it on later runs.
const appOwner = createAppOwner(
  createOwnerSecret({ randomBytes: createRandomBytes() }),
);

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

assertTrue(typeof createTodoEvolu === "function");
```

---

<a id="memoryonly"></a>

### memoryOnly?

```ts
readonly optional memoryOnly?: boolean;
```

Defined in: [packages/common/src/local-first/Evolu.ts:222](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/local-first/Evolu.ts#L222)

Keep local data only in memory instead of persisting it on this device.
Useful for testing, temporary data, or sensitive data that should not be
recoverable from local storage after the process ends.

Local data stored in memory is completely destroyed when the process ends.
Sync can still persist data remotely when transports are enabled.

The default value is: `false`.

---

<a id="ondatabasedeleted"></a>

### onDatabaseDeleted?

```ts
readonly optional onDatabaseDeleted?: () => void;
```

Defined in: [packages/common/src/local-first/Evolu.ts:276](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/local-first/Evolu.ts#L276)

Called when this instance's local database is deleted.

Apps can use this to update UI immediately because the corresponding
[Evolu](https://evolu.dev/docs/api-reference/common/local-first/Evolu/interfaces/Evolu) instance becomes unusable after local database deletion.

### onOwnerDeleted?

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

Defined in: [packages/common/src/local-first/Evolu.ts:284](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/local-first/Evolu.ts#L284)

Called when local data for an [Owner](https://evolu.dev/docs/api-reference/common/local-first/Owner/interfaces/Owner) is deleted.

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

### transports?

```ts
readonly optional transports?: readonly OwnerWebSocketTransport[];
```

Defined in: [packages/common/src/local-first/Evolu.ts:210](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/local-first/Evolu.ts#L210)

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](https://evolu.dev/docs/api-reference/common/local-first/Evolu/interfaces/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](https://evolu.dev/docs/api-reference/common/local-first/Owner/functions/createOwnerWebSocketTransport) to create WebSocket transport
configurations with proper URL formatting and [OwnerId](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/OwnerId) inclusion. The
[OwnerId](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/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

```ts
import {
  assertEqual,
  createAppOwner,
  createOwnerWebSocketTransport,
  createOwnerSecret,
  createRandomBytes,
  type OwnerTransport,
} from "@evolu/common";

// Create once, persist the mnemonic securely, and restore it on later runs.
const appOwner = createAppOwner(
  createOwnerSecret({ randomBytes: createRandomBytes() }),
);

// 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: appOwner.id,
  }),
];

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