> BLOG/POSTS/USING VARLOCK TO PULL SECRETS FROM 1PASSWORD AT RUNTIME
← Back to blog (or backspace)

Using varlock to pull secrets from 1Password at runtime

Mar 12 2026

No longer worry about having plaintext secrets floating around in your filesystem.

TL;DR: https://github.com/jesse-id/varlock-node-example

What is varlock?

I was listening to an episode of Syntax.fm yesterday (one of my favorite podcasts) called ”Stop putting secrets in .env”. This has been a longtime pain point for me, being an infinitely lazy — but also a security-minded — type of nerd. I’ve relied on self confidence in the past, assuming that my filesystem is protected because I’m not flippant with my own security practices. It still weirds me out to have plaintext secrets in .env files on my filesystem, nevertheless.

Phil Miller and Theo Ephraim were on the show to talk about their product varlock, which I hadn’t heard of before. It didn’t take much convincing after they briefly explained what it does because as it turns out, varlock does exactly what I want it to do.

It allows me to place 1Password secret references inside of my .env.local files instead of plaintext secrets, and then it injects them at runtime. Also, as a claude code evangelist, it adds a layer of protection against agents recording my secrets, which I hadn’t really thought of as a problem but yes, it totally is a big problem.

Is it easy?

I fumbled around a bit but it wasn’t too painful. The Getting Started docs are not as hand-holdy as I’d like them to be, but this is a young project and this thing can handle some pretty complicated use cases, so I get it.

Most of my struggles were centered on the front matter/headers in the .env.schema and .env.local files. They’re not really covered at all in the Getting Started section, so I was kind of flying blind and relying on experience and iterative debugging. The major sticking point was the 1Password plugin example.

brew install dmno-dev/tap/varlock && varlock init gets you most of the way there, but adding/using the 1Password plugin is not fleshed out very well in the docs, in my opinion.

The install docs shows the following example:

# @plugin(@varlock/1password-plugin) # load + install plugin
# @initOp(token=$OP_TOKEN, allowAppAuth=true) # init via custom root decorator
# ---
# @type=opServiceAccountToken # custom data type
OP_TOKEN=
# @sensitive
XYZ_API_KEY=op(op://api-prod/xyz/api-key) # custom resolver function

They don’t mention that $OP_TOKEN and the corresponding OP_TOKEN environment variable are meant for a remote 1Password server, which doesn’t make a ton of sense as the default use case in docs, because I would assume the problem that varlock solves is mostly a problem for local development? So I got tripped up debugging that for a bit. It’s possible that the explanation exists somewhere in the docs, but I am Captain Skimmer of the SS ADHD and ain’t nobody got time for that.

.env.local

# @plugin(@varlock/1password-plugin)
# @initOp(allowAppAuth=true)
# @defaultRequired=infer @defaultSensitive=false
# ----------

.env.schema

# @plugin(@varlock/1password-plugin, allowAppAuth=true)
# @defaultRequired=infer @defaultSensitive=false
# ----------

Why does .env.schema not include the @initOp line? Beats me. When I include it in .env.schema, I get kind of vague debugging until I remove it from .env.schema but keep it in .env.local, and then everything works like a champ.

🚨 Error(s) encountered in .env.schema
- Instance with id "_default" already initialized

🚨 🚨 🚨  Configuration is currently invalid   🚨 🚨 🚨

Invalid items:

⛔ VARLOCK_EXAMPLE_SECRET*  🔐sensitive
   └ undefined
   - error resolving value: SchemaError: Unable to authenticate with 1Password


💥 Resolved config/env did not pass validation 💥

Edit: Soon after initially cross-posting this blog entry to Hacker News, Theo Ephraim reached out to me on Discord (I recently joined their server) and pointed out that @plugin() is global so you only need it in one file, which would normally be the .env.schema file. That explains the error I ran into above. I essentially copied .env.schema to .env.local verbatim.

He also pointed out that .env.local is the convention rather than .env, so I made that change as well. Lastly, he said that import 'varlock/auto-load' and import { ENV } from 'varlock/env' are cool, so I added those to my example project as well.

Thanks Theo! I digress.

Is varlock good?

Oh yeah. It rules. Game changer. Once I figured out the front matter shenanigans, it was smooth sailing. I’m in the process of converting my dev projects with plaintext secrets in .env.local to 1Password secret references instead. Easy security win. I will also become an evangelist for this project amongst the other engineers I work with and I assume anyone who discovers it will be doing the same. I would be surprised if it’s not required learning in most programming courses and boot camps in the future.

Example Project

I quickly threw together an example project (https://github.com/jesse-id/varlock-node-example) that makes it easier to understand how this works in a local dev project and it also includes example usage of all of the different @type data types.

I also included .env.local and I will tell you that it gave me the ick to do that. I have never exposed a .env file in git before. Very knee-jerk ick. However, it’s safe because "secret reference" != "secret"! Hooray! Happy hacking!

> Loading comments...
> JESSE.ID
© 2026 All rights reserved by 👍👍 This Guy