npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@scalingworks/uenv

v0.2.0

Published

Load environment variables from secret vaults and run commands — keep secrets out of your repo

Readme

uenv

Load secrets from vaults and run commands — keep .env files out of your repository entirely.

@scalingworks/uenv is a CLI tool that bridges your secret vault (1Password today, others in future) and your local development workflow. Instead of committing .env files or copying secrets manually, uenv fetches them at runtime and injects them into your process.

Features

  • Three modes — envless (no local files at all), ref (.env with op:// references), plain (standard dotenv)
  • Push & pull — sync .env files to/from your vault with full section-level diffing
  • Monorepo-aware — each .env file in your repo maps to a named section inside a single vault item
  • Auto-inference — item name is derived from git remote get-url origin (e.g. scalingworks/my-app)
  • Provider-agnostic — 1Password ships first; the interface is open for AWS Secrets Manager, HashiCorp Vault, etc.

Requirements

Authentication

uenv supports two authentication modes depending on the environment.

Developer machines (interactive)

Set your account once with uenv config --account:

uenv config --account team.1password.com

When account is configured, uenv strips any OP_SERVICE_ACCOUNT_TOKEN from the environment and passes --account to every op call. The 1Password desktop app handles authentication — it will prompt for Touch ID or your password on the first call, then cache the session for subsequent calls in the same shell session.

This covers all three operations: run, push, and pull.

CI/CD (service account)

Leave account unconfigured. Set OP_SERVICE_ACCOUNT_TOKEN in your pipeline environment:

# No uenv config needed — token is picked up automatically
OP_SERVICE_ACCOUNT_TOKEN=ops_... uenv run node server.js

uenv passes the token through to op without modification. The service account needs at least read access to the vault. push and pull require a service account with write access (or run those from a developer machine instead).

Why OP_SERVICE_ACCOUNT_TOKEN is stripped on developer machines

If you have OP_SERVICE_ACCOUNT_TOKEN set in your shell (e.g. for another tool) and also have account configured in uenv, the token would normally override --account and authenticate as the service account. Service accounts often have restricted item access and are read-only — items created after the service account was provisioned may not be visible to it at all. Stripping the token forces op to use the interactive user session, which has full access to the vault.

Installation

npm install -g @scalingworks/uenv
# or
npx @scalingworks/uenv --help

Quick start

1. Configure your vault (one-time)

uenv config --vault envs
# optionally pin your 1Password account
uenv config --account team.1password.com

Config is saved to ~/.uenv/config.json.

2. Push your existing .env files to the vault

Run this from your repo root. uenv discovers every .env file and stores each one as a named section inside a single vault item whose title matches your repo name.

uenv push
# Pushing to vault "envs" › item "scalingworks/my-app"
# ✔ .env → 12 vars
# ✔ apps/web/.env → 5 vars
# ✔ apps/api/.env → 8 vars

You can now delete your local .env files and add them to .gitignore.

3. Run commands with secrets injected

uenv run npm start
uenv run go run ./cmd/server
uenv run docker-compose up

uenv fetches the .env section for this repo from the vault and injects it as environment variables before spawning your command. Nothing touches the filesystem.


Commands

uenv run

Load environment variables and execute a command.

uenv run [options] <command> [args...]

| Option | Default | Description | |--------|---------|-------------| | --mode | envless | envless | ref | plain — see Modes | | --vault | config / envs | Vault name | | --item | (repo name) | Item name inside the vault | | --section | .env | Which section (.env file path) to load | | --env-file | (section value) | Path to local file for ref/plain modes | | --provider | 1password | Secret provider |

# envless (default) — no local files needed
uenv run npm start

# target a non-root section (monorepo)
uenv run --section apps/web/.env next dev

# explicit item
uenv run --vault envs --item scalingworks/my-app node server.js

# ref mode — .env holds op:// URIs, resolved by op run
uenv run --mode ref npm run dev

# plain mode — standard dotenv, no vault involved
uenv run --mode plain --env-file .env.local jest

uenv push

Push local .env files to the vault. Each file becomes a section in the vault item. Removed keys are deleted from the vault (full sync).

uenv push [options] [files...]
# push every .env file in the repo
uenv push

# push specific files only
uenv push .env apps/api/.env

# override vault/item
uenv push --vault envs --item scalingworks/my-app

uenv pull

Pull vault sections back to local .env files. Creates directories as needed.

uenv pull [options] [sections...]
# pull all sections from the vault item
uenv pull

# pull a single section
uenv pull .env

# pull a nested section
uenv pull apps/web/.env

uenv config

View or update global configuration stored at ~/.uenv/config.json.

uenv config [options]
uenv config                          # show current config
uenv config --vault my-vault         # set default vault
uenv config --account team.1password.com

Modes

envless (recommended)

uenv loads variables from the vault and injects them into the spawned process. If a local .env file exists at the section path, its values are merged on top — local file wins.

process.env  <  vault  <  local .env file
uenv run npm start

This means you can delete .env files entirely and rely on the vault, or keep a local override file for dev-specific tweaks without pushing them to the vault.

ref

.env files contain op:// secret references instead of actual values. The file is safe to commit.

# .env  (safe to commit)
DATABASE_URL=op://envs/scalingworks-my-app/DATABASE_URL
STRIPE_SECRET_KEY=op://envs/scalingworks-my-app/STRIPE_SECRET_KEY
PORT=3000

uenv delegates to op run --env-file which resolves references on the fly.

uenv run --mode ref node server.js

plain

Standard dotenv behaviour. Reads a local .env file and injects variables. No vault interaction.

uenv run --mode plain jest
uenv run --mode plain --env-file .env.test pytest

Vault structure (1Password)

uenv stores all secrets for a repository in a single item whose title matches the inferred repository name:

Vault: envs
└── Item: scalingworks/my-app
    ├── Section: .env
    │   ├── DATABASE_URL  (concealed)
    │   ├── API_KEY       (concealed)
    │   └── NODE_ENV      (text)
    ├── Section: apps/web/.env
    │   ├── NEXT_PUBLIC_API_URL  (text)
    │   └── NEXT_PUBLIC_GA_ID   (text)
    └── Section: apps/api/.env
        ├── PORT          (text)
        └── JWT_SECRET    (concealed)
  • Vault — defaults to envs, configurable via uenv config --vault
  • Item title — inferred from git remote get-url origin; falls back to the current directory name
  • Section — the relative path of the .env file from the repository root
  • Field type — keys matching *SECRET*, *TOKEN*, *_KEY, *PASSWORD*, *PRIVATE*, etc. are stored as concealed; everything else is text

Adding a new secret

# 1. Edit your local .env
echo 'NEW_SERVICE_KEY=sk-...' >> .env

# 2. Push the change
uenv push .env

# 3. Other team members pull it
uenv pull .env

Or use op directly to edit the vault item and run uenv pull to sync locally.


Onboarding a new developer

# 1. Clone the repo (no .env files present)
git clone [email protected]:scalingworks/my-app.git
cd my-app

# 2. Pull all env sections from the vault
uenv pull

# 3. Start developing
uenv run npm start

Extending with a new provider

Implement the EnvProvider interface from src/providers/interface.ts:

import type { EnvProvider } from '@scalingworks/uenv';

export class MyProvider implements EnvProvider {
  readonly name = 'my-provider';

  async getEnv(vault: string, item: string, section: string): Promise<Record<string, string>> {
    // ...
  }

  async setEnv(vault: string, item: string, section: string, env: Record<string, string>): Promise<void> {
    // ...
  }

  async listSections(vault: string, item: string): Promise<string[]> {
    // ...
  }
}

Then register it in src/providers/index.ts.


License

MIT © Scaling Works