Skip to main content
Every config file passes through a handful of core operations: create it, load it, update it, and eventually delete it. tauri-plugin-configurate exposes a consistent builder-style API for all of these — each method returns a lazy entry you chain modifiers onto before executing with .run() or .unlock().

Setup

All examples on this page assume a schema and Configurate instance like the following:
src/lib/config.ts
import {
  BaseDirectory,
  Configurate,
  JsonProvider,
  defineConfig,
  keyring,
  optional,
} from "tauri-plugin-configurate-api";

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

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

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

create

config.create(data) creates a new config file. Pass the full config value as the argument. Because the schema contains a keyring() field, you must chain .lock(KEYRING) before .run() so the secret is routed to the OS keyring rather than written to disk.
// Returns a LockedConfig — keyring fields are null in .data
const locked = await config
  .create({
    theme: "dark",
    language: "en",
    database: { host: "localhost", password: "secret" },
  })
  .lock(KEYRING)
  .run();

console.log(locked.data.database.password); // null
Schemas without keyring() fields do not require .lock(). Call .run() directly: await config.create({ theme: "dark", language: "en" }).run().

load

config.load() reads the stored config file. Without .unlock(), keyring fields come back as null.
const locked = await config.load().run();
console.log(locked.data.database.password); // null

save

config.save(data) overwrites the entire config file with new data. Every field is replaced — use patch if you only want to update a subset of keys.
await config
  .save({
    theme: "light",
    language: "en",
    database: { host: "db.example.com", password: "new-secret" },
  })
  .lock(KEYRING)
  .run();

patch

config.patch(partial) deep-merges the provided keys into the stored config. Keys you omit are left unchanged. This follows RFC 7396 JSON Merge Patch semantics: setting a key to null overwrites the stored value; omitting a key leaves it untouched.
// Only "theme" is updated — all other fields stay as stored
await config.patch({ theme: "dark" }).run();
.createIfMissing() is useful during app startup when you want to ensure a config file exists without a separate exists() check. It is a no-op if the file is already present.

delete

config.delete(keyringOpts?) deletes the config file. Pass KeyringOptions to also remove associated keyring entries from the OS keyring.
// Removes the file AND wipes all keyring entries for this config
await config.delete(KEYRING);
Omitting keyringOpts on a schema with keyring() fields leaves orphaned entries in the OS keyring. Pass KEYRING unless you have a specific reason not to.

exists

config.exists() returns a boolean indicating whether the config file is present.
const present: boolean = await config.exists();
if (!present) {
  await config
    .create({ theme: "dark", language: "en", database: { host: "localhost", password: "secret" } })
    .lock(KEYRING)
    .run();
}

list

config.list() returns the names of all config files in the resolved root directory. For file-based providers, this scans for files matching the provider’s extension; backup files (.bak*) and temp files are excluded. For SQLite, it returns all config_key values in the table.
const files: string[] = await config.list();
// ["app.json", "user.json", "settings.json"]

reset

config.reset(data) deletes the existing config and immediately re-creates it with the data you provide. It is equivalent to calling delete followed by create, but in a single round-trip.
await config
  .reset({
    theme: "dark",
    language: "en",
    database: { host: "localhost", password: "secret" },
  })
  .lock(KEYRING)
  .run();

Operation summary

The table below shows which builder methods each operation supports.
Operation.lock().run().run().unlock().createIfMissing()
createYesYes (no keyring)YesNo
loadYesYesNo
saveYesYes (no keyring)YesNo
patchYesYesYesYes
resetYesYes (no keyring)YesNo
deletePass KeyringOptions directlyNo
existsDirect Promise<boolean>No
listDirect Promise<string[]>No

Build docs developers (and LLMs) love