Skip to content

Configuration files

notenv splits configuration across three files: one committed contract, one per-machine config, and one per-checkout binding. Secret values live in none of them. They are always encrypted in your vault.

notenv.toml (committed)

Lives in your project and is committed. It declares which environment variables the project needs. It contains no secret values.

namespace = "my-project"   # optional; defaults to the directory name

[secrets]
DATABASE_URL = {}                               # declared, and required by default
SENTRY_DSN   = { required = false }             # optional: run proceeds if it is missing
STRIPE_KEY   = { name = "stripe-secret-key" }   # use a different storage key name
Field Meaning
namespace The namespace this project reads. Defaults to the directory name. Pinned per checkout.
[secrets] KEY = { required = bool } Declare an environment variable. required defaults to true (declaring a secret means you need it), so run fails if it is missing; set required = false to make it optional.
{ name = "..." } Store the secret under a different key name than the environment variable.

~/.config/notenv/config.toml (per machine, not committed)

Defines one or more named storages (vaults). Written for you by notenv setup.

default = "personal"               # storage used when a project has no local binding

[storage.local]
path      = "~/.local/share/notenv/vaults/local"   # a local vault directory (no rclone)

[storage.personal]
remote    = "s3-notenv"            # an rclone remote name
base      = "my-bucket/notenv"     # path within the remote
versioned = true                   # remote keeps old versions on overwrite (B2 does)
# read_only = true                 # refuse mutating commands here (policy, not enforcement)
# cache_ttl = "1h"                 # ciphertext cache lifetime (remote storages only); "0" disables

[crypto]
mode = "passphrase"
# cache_ttl = "1h"                 # master-key cache lifetime; "0" disables

Storage entry fields

A storage is either a local vault (path) or a cloud remote (remote + base). Exactly one of the two forms is set.

Field Applies to Meaning
path local A local vault directory. Pure-Go backend, no rclone.
remote cloud An rclone remote name.
base cloud The path within the remote.
versioned cloud The remote retains old object versions on overwrite (B2 does natively), so notenv skips the extra server-side .prev backup copy.
read_only both Refuse every mutating command against this storage. Policy for cooperating clients, not enforcement; see Environment variables.
cache_ttl cloud Ciphertext cache lifetime. "0" disables. Remote storages only; a local vault does not blob-cache.

Crypto

Field Meaning
mode passphrase (the default unlock mode).
cache_ttl Master-key cache lifetime. "0" disables. Cached in the kernel keyring on Linux, the Keychain on macOS, DPAPI on Windows.

Storage settings are machine-only by design

A committed notenv.toml cannot redirect where your machine reads and writes secrets. Storage lives only in the per-machine config, so cloning a project can never repoint your storage.

notenv.local.toml (per checkout, not committed)

Written by notenv init and git-ignored. Records what this checkout has agreed to: which storage it uses (when the machine has several) and which namespace it reads.

The namespace pin matters: the committed contract chooses the namespace, so without the pin a cloned repository could silently point your machine at another project's secrets in the same vault. Using a namespace other than the directory's name is confirmed once per checkout, and a contract that later changes its namespace is refused until you re-accept it with notenv init. See Multiple vaults.