config.patch() handles this for you: it deep-merges the partial object you provide into the stored config, leaving every key you omit completely untouched. This guide explains how patching works, how it interacts with keyring-protected fields, and how to handle configs that might not yet exist.
How Patching Works
config.patch(partial) accepts a Partial<InferUnlocked<S>> and sends it to the plugin, which reads the current file, merges your partial data on top, and writes the result back. Only the keys present in your partial object are updated; everything else is preserved exactly as stored.
The merge follows JSON Merge Patch semantics (RFC 7396):
- Omitting a key leaves the stored value unchanged.
- Setting a key to
nullwritesnullinto the stored file — it does not delete or skip the key. - Providing a nested object recursively merges at that level, so you can update a single nested property without supplying the rest of the object.
config.patch() returns a LazyPatchEntry. You complete the operation by chaining a terminal method.
| Terminal method | Description | Returns |
|---|---|---|
.run() | Patch without keyring | Promise<PatchedConfig<S>> |
.lock(opts).run() | Patch and store keyring secrets | Promise<PatchedConfig<S>> |
.unlock(opts) | Patch, store keyring secrets, return unlocked result | Promise<UnlockedConfig<S>> |
.createIfMissing() | (modifier) Create config if not found instead of throwing | LazyPatchEntry<S> |
Basic Patch
Pass only the fields you want to change. All other stored keys remain as they are.PatchedConfig<S> exposes data typed as Partial<InferLocked<S>> — reflecting only the keys that were part of the patch, with keyring fields as null in the locked form.
Patching Keyring Fields
If your partial data includes a keyring-protected field, you must chain.lock(opts) before .run() so the plugin knows where to store the updated secret.
Get Unlocked Data After Patching
Chain.unlock(opts) instead of .lock(opts).run() to receive an UnlockedConfig<S> with keyring fields already populated — useful when you need to display or act on the new values immediately after patching.
Create If Missing
By default, patching a config that does not yet exist throws an error. Chain.createIfMissing() before .run() to create the file with the provided partial data instead of throwing.
Patching a config that does not exist will throw unless you chain
.createIfMissing(). If you are unsure whether the file has been created
yet, either check with config.exists() first or use .createIfMissing()
as a safe default..createIfMissing() with .lock() when your partial data contains keyring fields: