Skip to content

KeePass Plugin

Our KeePass plugin enables loading secrets from KDBX 4.0 database files using declarative instructions within your .env files.

It supports two modes of operation: file mode (default) reads .kdbx files directly using a pure WASM implementation, and CLI mode uses keepassxc-cli for development workflows with system-level key management (YubiKey, Windows Hello, etc.).

  • KDBX 4.0 support: reads KeePass database files directly via kdbxweb with pure WASM argon2
  • KeePassXC CLI integration: use keepassxc-cli for development workflows
  • Key file support: authenticate with password + optional key file
  • #attribute syntax: read any entry field (Password, UserName, URL, Notes, or custom fields)
  • Auto-infer entry paths from variable names for convenience
  • Custom attributes object: load all custom fields from a single entry for @setValuesBulk
  • Bulk loading with kpBulk() via @setValuesBulk to load all entries in a group
  • Multiple instances for accessing different databases

In a JS/TS project, you may install the @varlock/keepass-plugin package as a normal dependency. Otherwise you can just load it directly from your .env.schema file, as long as you add a version specifier. See the plugins guide for more instructions on installing plugins.

.env.schema
# 1. Load the plugin
# @plugin(@varlock/keepass-plugin)
#
# 2. Initialize with your database path and password
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD)
.env.schema
# @plugin(@varlock/keepass-plugin)
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD, keyFile="./secrets.keyx")

When useCli=true, the plugin uses keepassxc-cli to read entries instead of reading the file directly. This is useful during development when you want to use KeePassXC’s system integration.

The useCli option can be dynamic. For example, useCli=forEnv(dev) uses the CLI only in development:

.env.schema
# @plugin(@varlock/keepass-plugin)
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD, useCli=forEnv(dev))

You must have KeePassXC installed, which includes keepassxc-cli:

Terminal window
# macOS
brew install --cask keepassxc
# Ubuntu/Debian
sudo apt install keepassxc
# Fedora/RHEL
sudo dnf install keepassxc
# Arch
pacman -S keepassxc

See KeePassXC downloads for more options.

Access secrets from multiple databases using the id parameter:

.env.schema
# @plugin(@varlock/keepass-plugin)
# @initKeePass(id=prod, dbPath="./prod.kdbx", password=$KP_PROD_PASSWORD)
# @initKeePass(id=dev, dbPath="./dev.kdbx", password=$KP_DEV_PASSWORD)
# ---
PROD_SECRET=kp(prod, "Database/production")
DEV_SECRET=kp(dev, "Database/development")

Once the plugin is installed and initialized, you can start adding config items that load values using the kp() resolver function.

Fetch secrets using entry paths with #attribute syntax:

.env.schema
# Fetch password (default attribute) from an entry
DB_PASSWORD=kp("Database/production")
# Fetch a different attribute using #attribute syntax
DB_USER=kp("Database/production#UserName")
DB_URL=kp("Database/production#URL")
# Read a custom string field
API_KEY=kp("Services/stripe#SecretKey")

When the env var key matches a KeePass entry title, you can omit the entry path:

.env.schema
# Looks up entry titled "DB_PASSWORD", reads the Password field
DB_PASSWORD=kp()
# Looks up entry titled "DB_USER", reads the UserName field
DB_USER=kp("#UserName")

Entry paths use forward slashes to separate groups from the entry title:

Group/SubGroup/EntryTitle

For example, if your KeePass database has:

  • Root
    • Database
      • production (entry with Password, UserName fields)
    • Services
      • stripe (entry with a custom “SecretKey” field)

You would reference them as "Database/production" and "Services/stripe".

Use customAttributesObj=true to load all custom (non-standard) fields from a single entry as a JSON object. This is useful with @setValuesBulk to expand custom fields into env vars:

.env.schema
# Given an entry "Database/production" with custom fields: HOST, PORT, DB_NAME
# @setValuesBulk(kp("Database/production", customAttributesObj=true), createMissing=true)
# ---
HOST=
PORT=
DB_NAME=

Standard fields (Title, Password, UserName, URL, Notes) are excluded; only custom fields are included.

Use kpBulk() with @setValuesBulk to fetch the Password field from all entries under a group:

.env.schema
# @plugin(@varlock/keepass-plugin)
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD)
# @setValuesBulk(kpBulk(Production), createMissing=true)
# ---
# These will be populated from entries under the "Production" group
DB_PASSWORD=
API_KEY=

You can customize the scope:

.env.schema
# Load all entries from the database root
# @setValuesBulk(kpBulk())
# Load from a specific group
# @setValuesBulk(kpBulk("Services/APIs"))
# With a named instance
# @setValuesBulk(kpBulk(prod, Production))

Entry paths in the JSON output are sanitized to valid env var names (uppercased, non-alphanumeric characters replaced with underscores).


Initialize a KeePass plugin instance for accessing secrets from a KDBX database.

Key/value args:

  • dbPath (required): Path to the .kdbx database file
  • password (required): Master password (typically from an env var like $KP_PASSWORD)
  • keyFile (optional): Path to a key file for additional authentication
  • useCli (optional): Use keepassxc-cli instead of reading the file directly (default: false). Can be dynamic, e.g. useCli=forEnv(dev)
  • id (optional): Instance identifier for multiple databases
# Basic setup
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD)
# With key file and CLI mode
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD, keyFile="./key.keyx", useCli=true)
# Multiple instances
# @initKeePass(id=prod, dbPath="./prod.kdbx", password=$KP_PROD_PW)

This type is @internal by default: varlock uses it to fetch your other secrets but does not inject it into your application. Override with @internal=false if your app uses the credential directly, for example to write secrets back or fetch additional secrets at runtime.

A sensitive string type for KeePass database master passwords. Validates that the value is a non-empty string and is automatically marked as sensitive.

# @type=kdbxPassword @sensitive @internal
KP_PASSWORD=

Fetch a single entry field from a KeePass database. Returns the Password field by default.

Array args:

  • instanceId (optional): instance identifier when multiple plugin instances are initialized
  • entryPath (optional): path to the entry (uses #attribute for non-Password fields). If omitted, uses the variable name.

Key/value args:

  • attribute (optional): alternative to #attribute syntax for specifying the field to read
  • customAttributesObj (optional): if true, returns all custom fields as a JSON object (for use with @setValuesBulk)
# Default password field
DB_PASSWORD=kp("Database/production")
# Specific attribute via #attribute
DB_USER=kp("Database/production#UserName")
# Infer entry name from variable key
DB_PASSWORD=kp()
# Infer entry name + specify attribute
DB_USER=kp("#UserName")
# Custom fields as JSON object
# @setValuesBulk(kp("Database/production", customAttributesObj=true))
# With instance ID
SECRET=kp(prod, "Database/production")

Fetch the Password field from all entries under a group as a JSON map. Intended for use with @setValuesBulk.

Entry paths are sanitized to valid env var names (uppercased, non-alphanumeric replaced with underscores).

Array args:

  • instanceId (optional): instance identifier when multiple plugin instances are initialized
  • groupPath (optional): group path to load entries from (loads all entries if omitted)
# Load all entries from the database root
# @setValuesBulk(kpBulk())
# Load entries under a specific group
# @setValuesBulk(kpBulk(Production))
# With instance ID
# @setValuesBulk(kpBulk(prod, Production))

.env.schema
# @plugin(@varlock/keepass-plugin)
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD)
# ---
# @type=kdbxPassword @sensitive @internal
KP_PASSWORD=
DB_PASSWORD=kp("Database/production")
API_KEY=kp("Services/stripe#SecretKey")
SMTP_USER=kp("Email/smtp#UserName")
.env.schema
# @plugin(@varlock/keepass-plugin)
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD)
# @setValuesBulk(kpBulk(Production), createMissing=true)
# ---
# @type=kdbxPassword @sensitive @internal
KP_PASSWORD=
# These are auto-populated from entries in the "Production" group
DB_PASSWORD=
API_KEY=
REDIS_URL=
.env.schema
# @plugin(@varlock/keepass-plugin)
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD)
# @setValuesBulk(kp("Database/production", customAttributesObj=true), createMissing=true)
# ---
# @type=kdbxPassword @sensitive @internal
KP_PASSWORD=
# Custom fields from the "Database/production" entry
HOST=
PORT=
DB_NAME=
.env.schema
# @plugin(@varlock/keepass-plugin)
# @initKeePass(dbPath="./secrets.kdbx", password=$KP_PASSWORD, useCli=forEnv(dev))
# ---
# @type=kdbxPassword @sensitive @internal
KP_PASSWORD=
# In dev: reads via keepassxc-cli (YubiKey, etc.)
# In prod: reads the .kdbx file directly
DB_PASSWORD=kp("Database/production")

  • Check that the database password is correct
  • If using a key file, verify the path is correct and the file matches the database
  • Entry paths are case-sensitive
  • Use forward slashes to separate groups: "Group/SubGroup/Entry"
  • In CLI mode, list entries with: keepassxc-cli ls <database.kdbx>
  • Install KeePassXC which includes the CLI (see CLI mode)
  • Ensure keepassxc-cli is in your PATH
  • Check the dbPath value; it’s resolved relative to the working directory
  • Use an absolute path if needed
  • KeePassXC: cross-platform KeePass-compatible password manager
  • KeePass: original KeePass Password Safe
  • KDBX format: KeePass database format specification
  • kdbxweb: JavaScript KDBX reader library