Safety Rails
How vars prevents secrets from leaking with the public keyword, pre-commit hook, and Redacted types.
The encryption model is only useful if secrets never accidentally leave the encrypted state. vars has three safety rails to prevent that.
public keyword — opt-in plaintext
By default, every value is encrypted. The public keyword explicitly marks a variable as safe to commit in plaintext:
public APP_NAME = "my-app"
public PORT : z.number().int() = 3000If it's not public, it's encrypted. There's no way to accidentally leave a secret unencrypted — you have to deliberately opt out.
Public variables generate plain TypeScript types (string, number) instead of Redacted<string>, so the type system also reflects the security boundary.
Pre-commit hook
vars init installs a git pre-commit hook that blocks commits containing .unlocked.vars files:
error: .vars file is unlocked — run `vars hide` firstThe hook doesn't auto-encrypt — that would require the PIN, which requires a human. Instead, it stops the commit and tells you what to do. This is intentional: the PIN prompt is the gatekeeper between automated tools and your secrets.
If the hook is missing, vars doctor will detect and offer to reinstall it.
Redacted<T> — runtime leak prevention
When vars hands decrypted values to your TypeScript code, secret strings come wrapped in Redacted<T>:
const key = new Redacted("sk_live_abc123");
console.log(key); // <redacted>
console.log(`${key}`); // <redacted>
JSON.stringify({ key }); // {"key":"<redacted>"}toString(), toJSON(), and Node.js's util.inspect all return "<redacted>". The value stays hidden from logs, error reporters, and serializers.
To get the real value, call unwrap():
const actualKey = key.unwrap(); // "sk_live_abc123"unwrap() marks the exact spot where a secret is deliberately exposed, which makes it easy to grep for during code review.
Numbers and booleans are not wrapped — they can't leak meaningful information through toString(). The Redacted class is inlined in the generated .ts file with no runtime dependency.
The show/hide cycle
Secrets are only ever decrypted temporarily. vars show creates a .unlocked.vars working copy; vars hide encrypts it back. The .unlocked.vars file is gitignored, so even if you forget to hide, the pre-commit hook catches it.
For the full CLI reference, see Setup & Auth.