> ## 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.

# Configurate Class — Complete TypeScript API Reference

> Complete reference for the Configurate class: constructor, CRUD methods, patch, reset, exists, list, export, import, validate, watch, and batching.

The `Configurate<S>` class is the central object you interact with in tauri-plugin-configurate. You instantiate it once per configuration target — providing a schema, a file name, a base directory, and a storage provider — and then call its methods to create, load, save, patch, reset, export, import, validate, and watch your config. The generic parameter `S` is the schema type returned by `defineConfig()`, which flows through every method signature to give you end-to-end type safety.

## Constructor

```typescript theme={null}
new Configurate<S>(opts: ConfigurateInit<S>)
```

<ParamField path="schema" type="S" required>
  Schema object returned by `defineConfig()`. The type parameter `S` is inferred from this value and propagates through all method return types.
</ParamField>

<ParamField path="fileName" type="string" required>
  Name of the config file, including its extension (for example `"app.json"` or `"settings.toml"`). Must be a single filename — forward slashes (`/`) and back slashes (`\`) are not allowed. The values `"."` and `".."` are also rejected.
</ParamField>

<ParamField path="baseDir" type="BaseDirectory" required>
  A Tauri `BaseDirectory` enum value that determines the root location on disk. Import `BaseDirectory` from `@tauri-apps/api/path` or from `tauri-plugin-configurate-api`, which re-exports it.
</ParamField>

<ParamField path="provider" type="ConfigurateProvider" required>
  A storage provider returned by one of `JsonProvider()`, `YmlProvider()`, `TomlProvider()`, or `BinaryProvider()`. The provider controls the file format and optional encryption.
</ParamField>

<ParamField path="options" type="ConfiguratePathOptions">
  Optional path customization object.

  <Expandable title="ConfiguratePathOptions fields">
    <ParamField path="options.dirName" type="string">
      Replaces the app-identifier directory segment in the resolved path. Useful when you want configs stored under a custom folder name rather than the app bundle identifier.
    </ParamField>

    <ParamField path="options.currentPath" type="string">
      Adds a sub-directory under the resolved root. Segments must not be empty or the special values `"."` or `".."`.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField path="validation" type="SchemaValidationOptions">
  Controls when schema validation runs. All three fields default to `false`.

  <Expandable title="SchemaValidationOptions fields">
    <ParamField path="validation.validateOnWrite" type="boolean">
      When `true`, the full schema is checked against data passed to `create()` and `save()` before writing.
    </ParamField>

    <ParamField path="validation.validateOnRead" type="boolean">
      When `true`, the schema is checked against data returned by `load()` and `unlock()`.
    </ParamField>

    <ParamField path="validation.allowUnknownKeys" type="boolean">
      When `true`, keys present in the data but not declared in the schema do not cause validation to fail.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField path="defaults" type="Partial<InferUnlocked<S>>">
  Default values merged into loaded data when keys are absent from the stored file. Defaults are applied after migrations run.
</ParamField>

<ParamField path="version" type="number">
  Current schema version number. When provided, tauri-plugin-configurate stores a `__configurate_version__` field alongside your data and uses it to detect when migrations are needed.
</ParamField>

<ParamField path="migrations" type="MigrationStep[]">
  Ordered list of migration steps applied when loading data whose stored version is older than `version`. Each step describes a single version increment. Migrations run automatically on `load()`; if any migration runs, the migrated data is auto-saved back to storage.
</ParamField>

<ParamField path="backup" type="boolean">
  When `true`, rolling backup files (`.bak1`, `.bak2`, `.bak3`) are written before each destructive operation and removed automatically when the application exits. Defaults to `false`.
</ParamField>

### Quick-start example

```typescript theme={null}
import { Configurate, defineConfig, JsonProvider } from "tauri-plugin-configurate-api";
import { BaseDirectory } from "@tauri-apps/api/path";

const schema = defineConfig({
  theme: String,
  fontSize: Number,
});

const config = new Configurate({
  schema,
  fileName: "app.json",
  baseDir: BaseDirectory.AppConfig,
  provider: JsonProvider(),
  defaults: { theme: "light", fontSize: 14 },
  validation: { validateOnWrite: true },
});
```

***

## Instance Methods

### create(data)

Creates a new config file on disk and returns a lazy builder you chain before executing.

```typescript theme={null}
create(data: InferUnlocked<S>): LazyConfigEntry<S>
```

<ParamField path="data" type="InferUnlocked<S>" required>
  Full config object whose shape must match the schema. All required fields must be present.
</ParamField>

<ResponseField name="returns" type="LazyConfigEntry<S>">
  A chainable builder. Call `.run()` to execute, `.lock(opts).run()` to also store keyring fields, or `.unlock(opts)` to store keyring fields and immediately return the unlocked result.
</ResponseField>

```typescript theme={null}
// No keyring fields in schema
const locked = await config.create({ theme: "dark", fontSize: 16 }).run();

// Schema has keyring fields — use .lock() before .run()
const locked = await config
  .create({ theme: "dark", apiKey: "secret" })
  .lock({ service: "my-app", account: "default" })
  .run();

// Or get unlocked data back immediately
const unlocked = await config
  .create({ theme: "dark", apiKey: "secret" })
  .unlock({ service: "my-app", account: "default" });
```

***

### load()

Loads an existing config file from disk. Keyring-protected fields come back as `null` in the locked result unless you call `.unlock()`.

```typescript theme={null}
load(): LazyConfigEntry<S>
```

<ResponseField name="returns" type="LazyConfigEntry<S>">
  A chainable builder. Chain `.run()` for a locked result, or `.unlock(opts)` to populate keyring fields.
</ResponseField>

```typescript theme={null}
// Load with keyring fields as null
const locked = await config.load().run();
console.log(locked.data.apiKey); // null

// Load and populate keyring fields
const unlocked = await config.load().unlock({ service: "my-app", account: "default" });
console.log(unlocked.data.apiKey); // "secret"

// Unlock from an already-loaded LockedConfig
const unlocked2 = await locked.unlock({ service: "my-app", account: "default" });
```

<Note>
  When `defaults` or `migrations` are configured, they are applied automatically during `load()` before returning data to you.
</Note>

***

### save(data)

Fully overwrites the existing config file with the provided data. Every field is replaced; this is not a merge operation.

```typescript theme={null}
save(data: InferUnlocked<S>): LazyConfigEntry<S>
```

<ParamField path="data" type="InferUnlocked<S>" required>
  Complete replacement data for the config file.
</ParamField>

<ResponseField name="returns" type="LazyConfigEntry<S>">
  A chainable builder with `.run()`, `.lock(opts).run()`, and `.unlock(opts)`.
</ResponseField>

```typescript theme={null}
await config
  .save({ theme: "light", fontSize: 12, apiKey: "new-secret" })
  .lock({ service: "my-app", account: "default" })
  .run();
```

***

### patch(partial)

Deep-merges a partial object into the existing config. Only keys you supply are updated; all other keys remain unchanged. Uses JSON Merge Patch semantics (RFC 7396): setting a key to `null` writes `null` to that field.

```typescript theme={null}
patch(partial: Partial<InferUnlocked<S>>): LazyPatchEntry<S>
```

<ParamField path="partial" type="Partial<InferUnlocked<S>>" required>
  Partial config object. Only present keys are written.
</ParamField>

<ResponseField name="returns" type="LazyPatchEntry<S>">
  A chainable builder with `.run()`, `.lock(opts).run()`, `.createIfMissing()`, and `.unlock(opts)`.
</ResponseField>

```typescript theme={null}
// Update only the theme; fontSize is untouched
const patched = await config.patch({ theme: "dark" }).run();

// With keyring
const patched = await config
  .patch({ apiKey: "rotated-secret" })
  .lock({ service: "my-app", account: "default" })
  .run();

// Create the file if it does not already exist
const patched = await config
  .patch({ theme: "dark" })
  .createIfMissing()
  .run();

// Patch and immediately unlock keyring fields
const unlocked = await config
  .patch({ theme: "dark" })
  .unlock({ service: "my-app", account: "default" });
```

<Warning>
  By default `patch()` throws if the config file does not exist. Chain `.createIfMissing()` to create it from the partial data instead.
</Warning>

***

### reset(data)

Deletes the existing config and re-creates it from scratch with the provided data. Equivalent to `delete()` followed by `create()`, but performed atomically on the Rust side.

```typescript theme={null}
reset(data: InferUnlocked<S>): LazyConfigEntry<S>
```

<ParamField path="data" type="InferUnlocked<S>" required>
  Full replacement data for the re-created config.
</ParamField>

<ResponseField name="returns" type="LazyConfigEntry<S>">
  A chainable builder with `.run()`, `.lock(opts).run()`, and `.unlock(opts)`.
</ResponseField>

```typescript theme={null}
const locked = await config
  .reset({ theme: "light", fontSize: 14, apiKey: "fresh-key" })
  .lock({ service: "my-app", account: "default" })
  .run();

// Or unlock immediately
const unlocked = await config
  .reset({ theme: "light", fontSize: 14, apiKey: "fresh-key" })
  .unlock({ service: "my-app", account: "default" });
```

***

### delete(keyringOpts?)

Deletes the config file from disk. If the schema has keyring fields and you supply `keyringOpts`, the corresponding keyring entries are removed from the OS keyring as well.

```typescript theme={null}
delete(keyringOpts?: KeyringOptions | null): Promise<void>
```

<ParamField path="keyringOpts" type="KeyringOptions">
  When provided, removes associated keyring entries. Omit if your schema has no `keyring()` fields, or if you intentionally want to leave keyring entries intact.
</ParamField>

<ResponseField name="returns" type="Promise<void>" />

```typescript theme={null}
// Without keyring cleanup
await config.delete();

// With keyring cleanup
await config.delete({ service: "my-app", account: "default" });
```

***

### exists()

Checks whether the config file currently exists on disk.

```typescript theme={null}
exists(): Promise<boolean>
```

<ResponseField name="returns" type="Promise<boolean>">
  `true` if the file exists, `false` otherwise.
</ResponseField>

```typescript theme={null}
const present = await config.exists();
if (!present) {
  await config.create({ theme: "light", fontSize: 14 }).run();
}
```

***

### list()

Lists config file names in the resolved root directory. For file-based providers, files are filtered to the provider's extension; `.bak*` and temporary files are excluded. For SQLite, all `config_key` values in the table are returned.

```typescript theme={null}
list(): Promise<string[]>
```

<ResponseField name="returns" type="Promise<string[]>">
  Array of file names (including their extension) found in the root directory.
</ResponseField>

```typescript theme={null}
const files = await config.list();
// ["app.json", "settings.json", "user.json"]
```

***

### exportAs(format, keyringOpts?)

Serializes the current config data to a string in the requested format. Useful for backup, clipboard sharing, or cross-format migration.

```typescript theme={null}
exportAs(format: "json" | "yml" | "toml", keyringOpts?: KeyringOptions | null): Promise<string>
```

<ParamField path="format" type="&#x22;json&#x22; | &#x22;yml&#x22; | &#x22;toml&#x22;" required>
  Target serialization format for the exported string.
</ParamField>

<ParamField path="keyringOpts" type="KeyringOptions">
  When provided, keyring fields are unlocked and included in the export. Omit to export with keyring fields absent.
</ParamField>

<ResponseField name="returns" type="Promise<string>">
  Serialized config string in the requested format.
</ResponseField>

```typescript theme={null}
const json = await config.exportAs("json");
const yaml = await config.exportAs("yml");
const toml = await config.exportAs("toml");

// Include secrets in the export
const yamlWithSecrets = await config.exportAs("yml", {
  service: "my-app",
  account: "default",
});
```

***

### importFrom(content, format, keyringOpts?)

Parses a serialized config string and writes it to storage, replacing the current config entirely.

```typescript theme={null}
importFrom(content: string, format: "json" | "yml" | "toml", keyringOpts?: KeyringOptions | null): Promise<void>
```

<ParamField path="content" type="string" required>
  Serialized config string to import.
</ParamField>

<ParamField path="format" type="&#x22;json&#x22; | &#x22;yml&#x22; | &#x22;toml&#x22;" required>
  Format of the `content` string.
</ParamField>

<ParamField path="keyringOpts" type="KeyringOptions">
  Required when the schema includes `keyring()` fields and the import data contains values for those fields.
</ParamField>

<ResponseField name="returns" type="Promise<void>" />

```typescript theme={null}
await config.importFrom('{"theme":"dark","fontSize":16}', "json");
await config.importFrom("theme: dark\n", "yml");
await config.importFrom('theme = "dark"\n', "toml", {
  service: "my-app",
  account: "default",
});
```

***

### validate(data)

Validates a complete config object against the schema without writing anything to disk. Throws a descriptive error if validation fails.

```typescript theme={null}
validate(data: InferUnlocked<S>): void
```

<ParamField path="data" type="InferUnlocked<S>" required>
  Full config data to validate.
</ParamField>

```typescript theme={null}
try {
  config.validate({ theme: "dark", fontSize: 16 });
  console.log("Valid!");
} catch (e) {
  console.error(e.message);
}
```

***

### validatePartial(data)

Validates a partial config object against the schema. Only keys that are present in `data` are checked; absent keys do not cause validation to fail.

```typescript theme={null}
validatePartial(data: Partial<InferUnlocked<S>>): void
```

<ParamField path="data" type="Partial<InferUnlocked<S>>" required>
  Partial config data to validate.
</ParamField>

```typescript theme={null}
config.validatePartial({ theme: "dark" });   // OK — only checks "theme"
config.validatePartial({ theme: 123 });      // throws — wrong type
```

***

### onChange(callback)

Registers a callback that fires whenever this config is changed by any operation (`create`, `save`, `patch`, `delete`, `reset`, `import`). Changes originating from external processes are reported by `watchExternal()` instead.

```typescript theme={null}
onChange(callback: (event: ConfigChangeEvent) => void): Promise<() => void>
```

<ParamField path="callback" type="(event: ConfigChangeEvent) => void" required>
  Function invoked with a `ConfigChangeEvent` whenever the config changes.
</ParamField>

<ResponseField name="returns" type="Promise<() => void>">
  A synchronous unlisten function. Call it when you no longer need the listener to avoid memory leaks.
</ResponseField>

```typescript theme={null}
const unlisten = await config.onChange((event) => {
  console.log(`${event.operation} on ${event.fileName}`);
});

// Later, when the component is unmounted:
unlisten();
```

***

### watchExternal(callback)

Watches the config file for changes made by processes outside your application. Only available for file-based providers; calling this with a non-file provider throws an error.

```typescript theme={null}
watchExternal(callback: (event: ConfigChangeEvent) => void): Promise<() => Promise<void>>
```

<ParamField path="callback" type="(event: ConfigChangeEvent) => void" required>
  Function invoked when an external change is detected. The `event.operation` value will be `"external_change"`.
</ParamField>

<ResponseField name="returns" type="Promise<() => Promise<void>>">
  An async stop function. Await it to unregister the file watcher on the Rust side and remove the JavaScript listener.
</ResponseField>

```typescript theme={null}
const stopWatching = await config.watchExternal((event) => {
  console.log("File changed externally — reloading…");
  // reload your data here
});

// Later:
await stopWatching();
```

<Warning>
  `watchExternal()` is only supported for file-based providers (JSON, YAML, TOML, Binary). It throws for SQLite.
</Warning>

***

## Static Methods

The three static batch methods let you load, save, or patch multiple configs in a single IPC round-trip, significantly reducing overhead when you manage several config files.

### Configurate.loadAll(entries)

Loads multiple configs in one IPC call. Post-load processing (defaults, migrations) is applied to each entry individually after the batch returns.

```typescript theme={null}
static loadAll(entries: LoadAllEntry[]): LoadAllRunner
```

<ParamField path="entries" type="LoadAllEntry[]" required>
  Array of `{ id: string; config: Configurate<any> }` objects. Each `id` must be unique within the batch.
</ParamField>

<ResponseField name="returns" type="LoadAllRunner">
  A builder with `.unlock(id, opts)`, `.unlockAll(opts)`, and `.run()`.
</ResponseField>

```typescript theme={null}
const result = await Configurate.loadAll([
  { id: "app", config: appConfig },
  { id: "secret", config: secretConfig },
])
  .unlock("secret", { service: "my-app", account: "default" })
  // .unlockAll({ service: "my-app", account: "default" }) — or unlock everything
  .run();

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

***

### Configurate.saveAll(entries)

Saves multiple configs in one IPC call.

```typescript theme={null}
static saveAll(entries: SaveAllEntry[]): SaveAllRunner
```

<ParamField path="entries" type="SaveAllEntry[]" required>
  Array of `{ id: string; config: Configurate<any>; data: unknown }` objects.
</ParamField>

<ResponseField name="returns" type="SaveAllRunner">
  A builder with `.lock(id, opts)`, `.lockAll(opts)`, and `.run()`.
</ResponseField>

```typescript theme={null}
const result = await Configurate.saveAll([
  { id: "app", config: appConfig, data: { theme: "dark", fontSize: 14 } },
  { id: "secret", config: secretConfig, data: { token: "tok" } },
])
  .lock("secret", { service: "my-app", account: "default" })
  // .lockAll({ service: "my-app", account: "default" }) — or lock everything
  .run();
```

***

### Configurate.patchAll(entries)

Patches multiple configs in one IPC call.

```typescript theme={null}
static patchAll(entries: PatchAllEntry[]): PatchAllRunner
```

<ParamField path="entries" type="PatchAllEntry[]" required>
  Array of `{ id: string; config: Configurate<any>; data: unknown }` objects where `data` is a partial config.
</ParamField>

<ResponseField name="returns" type="PatchAllRunner">
  A builder with `.lock(id, opts)`, `.lockAll(opts)`, and `.run()`.
</ResponseField>

```typescript theme={null}
const result = await Configurate.patchAll([
  { id: "app", config: appConfig, data: { theme: "light" } },
])
  .lock("app", { service: "my-app", account: "default" })
  .run();
```

<Tip>
  Batch operations are ideal at application startup when you need to load several config files before rendering the UI. One IPC call replaces N individual calls and reduces perceived latency.
</Tip>
