> ## Documentation Index
> Fetch the complete documentation index at: https://configurate.crystaworld.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Load and Save Multiple Configs in a Single IPC Call

> Use Configurate.loadAll(), saveAll(), and patchAll() to operate on multiple configuration files in one IPC round-trip for better performance.

Tauri's IPC layer has a per-call overhead: each invoke crosses the process boundary between your frontend and the Rust backend. If your app manages several config files — for example, separate files for application settings, user preferences, and workspace state — loading them one by one multiplies that overhead. The batch API collapses multiple operations into a single IPC call, so you pay the crossing cost exactly once regardless of how many configs you touch.

<Note>
  Each batch call supports a maximum of **128 entries**. If you need to operate
  on more configs than that, split them across multiple batch calls.
</Note>

The batch methods are static methods on the `Configurate` class. You assemble a list of entries — each carrying an `id` string, the `Configurate` instance, and (for write operations) the data — then chain keyring options and call `.run()`.

```typescript theme={null}
import {
  BaseDirectory,
  Configurate,
  JsonProvider,
  YmlProvider,
  defineConfig,
  keyring,
} from "tauri-plugin-configurate-api";

const appSchema = defineConfig({ theme: String, locale: String });
const userSchema = defineConfig({
  name: String,
  token: keyring(String, { id: "api-token" }),
});

const appConfig = new Configurate({
  schema: appSchema,
  fileName: "app.json",
  baseDir: BaseDirectory.AppConfig,
  provider: JsonProvider(),
});

const userConfig = new Configurate({
  schema: userSchema,
  fileName: "user.yml",
  baseDir: BaseDirectory.AppConfig,
  provider: YmlProvider(),
});

const KEYRING = { service: "my-app", account: "default" };
```

***

## Configurate.loadAll(entries)

`Configurate.loadAll(entries)` loads every config in the list and returns a `BatchRunResult` whose `results` map is keyed by the `id` you assigned each entry.

Unlock a specific entry by chaining `.unlock(id, keyringOpts)`, or unlock every entry at once with `.unlockAll(keyringOpts)`.

<Note>
  Batch loads apply the same post-load processing as individual `config.load()`
  calls — including `defaults` merging and automatic schema migration. You do
  not need any extra steps to benefit from these features in a batch context.
</Note>

```typescript theme={null}
const result = await Configurate.loadAll([
  { id: "app", config: appConfig },
  { id: "user", config: userConfig },
])
  .unlock("user", KEYRING)    // unlock only the "user" entry
  // .unlockAll(KEYRING)      // alternatively, unlock all entries
  .run();

if (result.results.app.ok) {
  console.log(result.results.app.data);
} else {
  console.error(result.results.app.error);
}
```

***

## Configurate.saveAll(entries)

`Configurate.saveAll(entries)` saves all entries in a single IPC call. Each entry carries its full replacement data alongside the `Configurate` instance.

Lock a specific entry's keyring fields with `.lock(id, keyringOpts)`, or lock all entries at once with `.lockAll(keyringOpts)`.

```typescript theme={null}
const result = await Configurate.saveAll([
  { id: "app",  config: appConfig,  data: { theme: "dark", locale: "en" } },
  { id: "user", config: userConfig, data: { name: "Alice", token: "tok_123" } },
])
  .lock("user", KEYRING)    // store the "user" entry's keyring fields
  // .lockAll(KEYRING)       // alternatively, lock all entries
  .run();

if (!result.results.user.ok) {
  console.error("Failed to save user config:", result.results.user.error);
}
```

***

## Configurate.patchAll(entries)

`Configurate.patchAll(entries)` applies a deep-merge patch to each config in a single IPC call. Like the individual `config.patch()`, only the keys you provide are updated; all other stored keys are left unchanged.

```typescript theme={null}
const result = await Configurate.patchAll([
  { id: "app",  config: appConfig,  data: { theme: "light" } },
  { id: "user", config: userConfig, data: { name: "Bob" } },
])
  .lock("user", KEYRING)   // required if the patch includes keyring fields
  .run();
```

***

## BatchRunResult

Every batch method returns a `BatchRunResult` after `.run()` resolves. Each entry in `results` is independently either a success or a failure, so a single bad config file does not abort the rest of the batch.

```typescript theme={null}
interface BatchRunResult {
  results: Record<
    string,
    | { ok: true;  data: unknown }
    | { ok: false; error: { kind: string; message: string } }
  >;
}
```

Always check `result.ok` before accessing `result.data`. Accessing `data` on a failed result entry is a type error.

<Tip>
  Iterate over all results in a loop to handle each entry consistently:

  ```typescript theme={null}
  for (const [id, entry] of Object.entries(result.results)) {
    if (entry.ok) {
      console.log(`[${id}] loaded:`, entry.data);
    } else {
      console.warn(`[${id}] failed — ${entry.error.kind}: ${entry.error.message}`);
    }
  }
  ```
</Tip>
