Skip to main content
Configurate is the central class in tauri-plugin-configurate. It ties a schema to a storage location and a provider, and exposes a consistent builder-style API for every config operation. You create one instance per config file and reuse it throughout your app.

Constructor

new Configurate<S>(opts: ConfigurateInit<S>)

Required options

opts.schema
SchemaObject
required
Schema object created with defineConfig(). TypeScript infers all value types from this. All keyring() IDs in the schema must be unique — the constructor throws if any are duplicated.
opts.fileName
string
required
The config file name. Must not contain path separators (/ or \) and must not be "." or "..".
opts.baseDir
BaseDirectory
required
Tauri BaseDirectory enum value that sets the root of the resolved path (e.g. BaseDirectory.AppConfig, BaseDirectory.AppData, BaseDirectory.Desktop).
opts.provider
ConfigurateProvider
required
Storage provider created by one of the provider functions: JsonProvider(), YmlProvider(), TomlProvider(), BinaryProvider(), or SqliteProvider(). See the providers reference.

Path options

opts.options.dirName
string
Replaces the app-identifier directory segment when it is the last segment of the baseDir path; otherwise appended as a sub-directory. Must not contain empty or special segments (., ..).
opts.options.currentPath
string
Sub-directory appended after the dirName root. Must not contain empty or special segments.

Validation options

opts.validation.validateOnWrite
boolean
default:"false"
When true, full schema validation runs before every create or save operation. Throws if the data does not match the schema.
opts.validation.validateOnRead
boolean
default:"false"
When true, full schema validation runs after every load or unlock operation. Throws if the loaded data does not match the schema.
opts.validation.allowUnknownKeys
boolean
default:"false"
When true, keys not declared in the schema are permitted and do not cause validation to fail.

Defaults, versioning, and backups

opts.defaults
Partial<InferUnlocked<S>>
Default values to fill in when loading a config that has missing keys. Applied after migrations, before returning data to the caller.
opts.version
number
Current schema version. When set, a __configurate_version__ field is stored alongside the data and used to detect configs that need migration.
opts.migrations
MigrationStep[]
Ordered list of migration steps applied automatically when loading an older config. Each step has a version number (the version it upgrades from) and an up function that transforms the data. See MigrationStep in result types.
opts.backup
boolean
default:"false"
When true, a rolling backup (.bak1.bak3) is created before each write and deleted automatically when the application exits. Applies only to file-based providers — has no effect with SqliteProvider.

Constructor example

src/lib/config.ts
import {
  Configurate,
  JsonProvider,
  BaseDirectory,
  defineConfig,
  keyring,
  optional,
} from "tauri-plugin-configurate-api";

const schema = defineConfig({
  theme: String,
  fontSize: optional(Number),
  database: {
    host: String,
    password: keyring(String, { id: "db-password" }),
  },
});

const config = new Configurate({
  schema,
  fileName: "app.json",
  baseDir: BaseDirectory.AppConfig,
  provider: JsonProvider(),
  options: {
    dirName: "my-app",
    currentPath: "config/v2",
  },
  validation: {
    validateOnWrite: true,
    validateOnRead: false,
    allowUnknownKeys: false,
  },
  defaults: {
    theme: "dark",
    fontSize: 14,
  },
  version: 2,
  migrations: [
    { version: 0, up: (data) => ({ ...data, newField: "default" }) },
    { version: 1, up: (data) => { delete (data as Record<string, unknown>).oldField; return data; } },
  ],
  backup: true,
});
// Resolved path: {AppConfig}/my-app/config/v2/app.json

Instance methods

create(data)

Creates a new config file with the provided data. If the schema has keyring() fields, you must chain .lock(keyringOpts) before .run().
data
InferUnlocked<S>
required
Full config data to write. All required fields must be present.
Returns: LazyConfigEntry<S> — a deferred entry with the following methods:
MethodReturnsDescription
.run()Promise<LockedConfig<S>>Execute and return locked data (keyring fields are null)
.lock(opts).run()Promise<LockedConfig<S>>Store secrets in keyring, return locked data
.unlock(opts)Promise<UnlockedConfig<S>>Store secrets in keyring, return unlocked data
const KEYRING = { service: "my-app", account: "default" };

// Without keyring fields
const locked = await config.create({ theme: "dark", fontSize: 14 }).run();

// With keyring fields — must use .lock()
const locked = await config
  .create({ theme: "dark", database: { host: "localhost", password: "secret" } })
  .lock(KEYRING)
  .run();

// Get unlocked data back immediately
const unlocked = await config
  .create({ theme: "dark", database: { host: "localhost", password: "secret" } })
  .unlock(KEYRING);

load()

Loads an existing config file. Without unlocking, keyring fields come back as null. Returns: LazyConfigEntry<S>
// Locked — keyring fields are null
const locked = await config.load().run();
console.log(locked.data.database.password); // null

// Unlocked — keyring fields are populated from the OS keyring
const unlocked = await config.load().unlock(KEYRING);
console.log(unlocked.data.database.password); // "secret"

// Unlock an already-loaded locked result
const unlocked2 = await locked.unlock(KEYRING);
defaults and migrations are applied automatically on every load() call. If a migration runs, the migrated data is auto-saved back to storage.

save(data)

Overwrites the entire config file with the provided data. All keys are replaced — omitted keys are removed.
data
InferUnlocked<S>
required
Full config data to write. Replaces all existing content.
Returns: LazyConfigEntry<S>
await config
  .save({ theme: "light", database: { host: "db.example.com", password: "new-secret" } })
  .lock(KEYRING)
  .run();

patch(partial)

Deep-merges partial into the existing config. Only provided keys are updated — omitted keys are left unchanged. Uses JSON Merge Patch semantics (RFC 7396): setting a key to null overwrites the stored value with null.
partial
Partial<InferUnlocked<S>>
required
Partial config data to merge. Only the keys you provide are updated.
Returns: LazyPatchEntry<S> — a deferred entry with the following methods:
MethodReturnsDescription
.run()Promise<PatchedConfig<S>>Execute patch, return locked result
.lock(opts).run()Promise<PatchedConfig<S>>Patch with keyring, return locked result
.createIfMissing()thisCreate the config if it does not exist instead of throwing
.unlock(opts)Promise<UnlockedConfig<S>>Patch with keyring, return unlocked result
// Simple patch — no keyring
const patched = await config.patch({ theme: "dark" }).run();

// Patch with keyring
const patched = await config.patch({ database: { password: "new-secret" } }).lock(KEYRING).run();

// Create if the config does not yet exist
await config.patch({ theme: "dark" }).createIfMissing().run();

delete(keyringOpts?)

Deletes the config file and wipes all associated keyring entries.
keyringOpts
KeyringOptions
Keyring credentials. Required when the schema has keyring() fields so that their stored secrets are wiped from the OS keyring on deletion.
Returns: Promise<void>
// Without keyring fields
await config.delete();

// With keyring fields
await config.delete(KEYRING);

exists()

Checks whether the config entry exists in storage. Returns: Promise<boolean>
const present: boolean = await config.exists();

list()

Lists config file names in the resolved root directory.
  • For file-based providers (JSON, YAML, TOML, Binary): scans the directory for files matching the provider’s extension. Backup files (.bak*) and temp files are excluded.
  • For SQLite: returns all config_key values in the table.
Returns: Promise<string[]>
const files: string[] = await config.list();
// ["app.json", "user.json", "settings.json"]

reset(data)

Deletes the existing config and re-creates it with the provided data. Equivalent to delete() followed by create(), but executed as a single atomic operation.
data
InferUnlocked<S>
required
Full config data to write after deletion.
Returns: LazyResetEntry<S> — a deferred entry with the following methods:
MethodReturnsDescription
.run()Promise<LockedConfig<S>>Reset and return locked data
.lock(opts).run()Promise<LockedConfig<S>>Reset with keyring, return locked data
.unlock(opts)Promise<UnlockedConfig<S>>Reset with keyring, return unlocked data
const locked = await config
  .reset({ theme: "dark", language: "en", database: { host: "localhost", password: "secret" } })
  .lock(KEYRING)
  .run();

exportAs(format, keyringOpts?)

Exports the stored config data as a formatted string. Optionally unlocks keyring fields before exporting so that secrets are included in the output.
format
"json" | "yml" | "toml"
required
Target serialization format for the exported string.
keyringOpts
KeyringOptions
When provided, keyring fields are unlocked from the OS keyring before serialization, so the exported string includes the decrypted secret values.
Returns: Promise<string>
const jsonStr  = await config.exportAs("json");
const yamlStr  = await config.exportAs("yml");
const tomlStr  = await config.exportAs("toml");

// Include decrypted secrets in the export
const yamlWithSecrets = await config.exportAs("yml", KEYRING);

importFrom(content, format, keyringOpts?)

Imports config data from a string, replacing the current stored config.
content
string
required
Serialized config string to import.
format
"json" | "yml" | "toml"
required
Source format of the string.
keyringOpts
KeyringOptions
Required when importing data that contains values for keyring() fields, so that the imported secrets are stored in the OS keyring instead of being written to disk.
Returns: Promise<void>
await config.importFrom('{"theme": "dark"}', "json");
await config.importFrom("theme: dark\n", "yml");
await config.importFrom('theme = "dark"\n', "toml", KEYRING);

validate(data)

Validates full config data against the schema without writing to storage. Throws a descriptive error on failure.
data
InferUnlocked<S>
required
Full config data to validate.
Returns: void — throws on validation failure.
try {
  config.validate({ theme: "dark", database: { host: "localhost", password: "secret" } });
  console.log("Valid!");
} catch (e) {
  console.error("Validation failed:", e.message);
}

validatePartial(data)

Validates partial config data against the schema without writing to storage. Only the provided keys are checked.
data
Partial<InferUnlocked<S>>
required
Partial config data to validate.
Returns: void — throws on validation failure.
config.validatePartial({ theme: "dark" }); // OK
config.validatePartial({ theme: 123 });    // throws — wrong type

watchExternal(callback)

Starts watching the config file for changes made by external processes. File-based providers only — throws if called with SqliteProvider.
callback
(event: ConfigChangeEvent) => void
required
Function called whenever an external change is detected. Receives a ConfigChangeEvent with operation: "external_change".
Returns: Promise<() => Promise<void>> — an async stop function. Call it to unregister the listener and stop the file watcher.
const stopWatching = await config.watchExternal((event) => {
  console.log(`External change detected: ${event.fileName}`);
});

// Later, stop watching
await stopWatching();

onChange(callback)

Registers a callback that fires whenever this config is changed by any in-app operation: create, save, patch, delete, reset, or import.
callback
(event: ConfigChangeEvent) => void
required
Function called after any in-app config change. Receives a ConfigChangeEvent describing the operation.
Returns: Promise<() => void> — a synchronous unlisten function. Call it to deregister the callback.
const unlisten = await config.onChange((event) => {
  console.log(`Config ${event.operation} on ${event.fileName}`);
});

// Later, stop listening
unlisten();

Static batch methods

Batch methods send multiple config operations in a single IPC round-trip. A failure in one entry does not abort the batch — each entry reports its own success or failure in the result.

Configurate.loadAll(entries)

Loads multiple configs in a single IPC call. Applies defaults and migrations to each entry after loading.
entries
Array<{ id: string; config: Configurate }>
Array of entries to load. Each entry has a unique string id and a Configurate instance.
Returns: A LoadAllRunner with:
  • .unlock(id, opts) — unlock a specific entry by ID
  • .unlockAll(opts) — unlock all entries with the same keyring options
  • .run() — execute and return Promise<BatchRunResult>
const result = await Configurate.loadAll([
  { id: "app", config: appConfig },
  { id: "secret", config: secretConfig },
])
  .unlock("secret", KEYRING)
  .run();

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

Configurate.saveAll(entries)

Saves multiple configs in a single IPC call.
entries
Array<{ id: string; config: Configurate; data: unknown }>
Array of entries to save. Each entry has a unique id, a Configurate instance, and the data to write.
Returns: A SaveAllRunner with:
  • .lock(id, opts) — lock a specific entry by ID
  • .lockAll(opts) — lock all entries with the same keyring options
  • .run() — execute and return Promise<BatchRunResult>
const result = await Configurate.saveAll([
  { id: "app", config: appConfig, data: { theme: "dark" } },
  { id: "secret", config: secretConfig, data: { token: "tok" } },
])
  .lock("secret", KEYRING)
  .run();

Configurate.patchAll(entries)

Patches multiple configs in a single IPC call.
entries
Array<{ id: string; config: Configurate; data: unknown }>
Array of entries to patch. Each entry has a unique id, a Configurate instance, and the partial data to merge.
Returns: A PatchAllRunner with:
  • .lock(id, opts) — lock a specific entry by ID
  • .lockAll(opts) — lock all entries with the same keyring options
  • .run() — execute and return Promise<BatchRunResult>
const result = await Configurate.patchAll([
  { id: "app", config: appConfig, data: { theme: "light" } },
])
  .lock("app", KEYRING)
  .run();

Build docs developers (and LLMs) love