Skip to content

Secrets management

varlock uses the term sensitive to describe any value that should not be exposed to the outside world. This includes secret api keys, passwords, and other generally sensitive information. Instead of relying on prefixes (e.g., NEXT_PUBLIC_) to know which items may be “public”, varlock relies on @decorators to mark sensitive items explicitly.

Whether each item is sensitive or not is controlled by the @defaultSensitive root decorator and the @sensitive item decorator. Whether you want to default to sensitive or not, or infer based on key names is up to you. For example:

.env.schema
# @defaultSensitive=false
# ---
# not sensitive by default (because of the root decorator)
NON_SECRET_FOO=
# @sensitive # explicitly marking this item as sensitive
SECRET_FOO=

varlock provides official plugins for popular secret management platforms, offering a seamless and type-safe way to fetch secrets directly in your .env files.

Available plugins include:

See the plugins overview for the complete list.

Plugins are able to register new decorators and resolver functions that declaratively fetch secrets:

# Install and initialize the 1Password plugin
# @plugin(@varlock/1password-plugin)
# @initOp(token=$OP_TOKEN, allowAppAuth=forEnv(dev))
# ---
# Load secrets using the op() resolver function
# @sensitive @required
MY_SECRET=op(op://my-vault/item-name/field-name)

Benefits of using plugins:

  • Declarative secret references safe to check into version control
  • Built-in validation and type safety applied to fetched values
  • Built-in authentication handling
  • Better error messages and debugging
  • Platform-specific features (e.g., biometric unlock for 1Password)

See each plugin’s documentation for detailed setup instructions.

For cases where a plugin doesn’t exist or you need custom logic, varlock supports fetching secrets via CLI commands using exec() function syntax.

# A secret fetched via CLI
# @sensitive @required
MY_SECRET=exec(`op read "op://devTest/myVault/credential"`);

This approach works with any CLI tool, ensuring no secrets are left in plaintext on your system, even if they are gitignored.

For some secret management platforms, you may already be setting key names that match your environment variable names - in which case, wiring up each value can feel like a lot of boilerplate.

In case like this, you can set many values at once using the @setValuesBulk() root decorator.

For example, using 1Password, you could store a .env style blob within a text field, or you could fetch values from their new environments tool.

.env.schema
# fetch a dotenv style blob within a text field
# @setValuesBulk(op("op://vault/field/item"))
#
# load values in a 1Password environment
# @setValuesBulk(opLoadEnvironment(your-environment-id), createMissing=true)
#
# load all secrets from an Infisical project environment
# @setValuesBulk(infisicalBulk())
#
# load Infisical secrets filtered by path or tag
# @setValuesBulk(infisicalBulk(path="/database", tag="backend"))
#
# Fetch all secrets from HashiCorp Vault as JSON
# @setValuesBulk(exec("vault kv get -format=json secret/myapp"), format=json)

The bulk values are injected at the precedence level of the file containing the decorator — so .env.local and process.env will still override them as expected. See the reference docs for full details.

Unlike other tools where you have to rely on pattern matching to detect sensitive-looking data, varlock knows exactly which values are sensitive, and can take extra precautions to protect them.

For example, some of the features supported by our libraries and integrations:

  • Redact sensitive values from logs
  • Scan client-facing bundled code at build time
  • Scan outgoing HTTP responses at runtime
  • Pre-commit git hooks to keep sensitive values out of version control

The varlock scan command checks your project files for any plaintext occurrences of your @sensitive values. It loads your varlock config, resolves all sensitive values, and then searches through files to detect leaks.

Terminal window
varlock scan

This is intended to be used as a pre-commit git hook to prevent accidentally committing secrets into version control. If no sensitive values are found in plaintext, it exits successfully. If any are detected, it reports the file, line number,and which secret was found, then exits with a non-zero status code.

  • varlock scan - default mode, scans all files except gitignored ones
  • varlock scan --include-ignored - scans all files including gitignored ones
  • varlock scan --staged - scans only the files you have staged for commit

The easiest way to set this up is:

Terminal window
varlock scan --install-hook

This will detect if you use a hook manager (like husky or lefthook) and provide appropriate instructions. If no hook manager is detected, it will create a .git/hooks/pre-commit script for you.

If you prefer to set it up yourself, add the following to your pre-commit hook:

Plain git hook (.git/hooks/pre-commit):

#!/bin/sh
varlock scan

Make sure the hook file is executable:

Terminal window
chmod +x .git/hooks/pre-commit

With husky (.husky/pre-commit):

Terminal window
varlock scan

With lefthook (lefthook.yml):

pre-commit:
commands:
varlock-scan:
run: varlock scan