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.
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.
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().
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).
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.
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).
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.
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.
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.
Iterate over all results in a loop to handle each entry consistently: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}`);
}
}