跳到正文
DEV Community· uehara·· 4 小時前AI 評分39

dotvault:以一次 pull 在手提電腦、CI 和雲端開發環境使用同一份 .env

One dotvault pull, the same .env everywhere: laptop, CI, cloud dev environments

AI 導讀

dotvault 透過 dotvault pull,讓手提電腦、CI 及雲端開發環境按同一方式取得同一專案的 .env 變數。每個環境只需安裝、登入及初始化一次;CI、伺服器和自行運作的 AI Agent 則使用服務 token。使用 dotvault run -- 可略過 .env 檔案,直接把變數傳給指定程序。

正文

This is part 2 of the series "dotvault, Start to Finish: One Command from Your Laptop to CI, Your Team, and Your AI Agents." dotvault will be released free of charge when this series ends.

A .env rarely lives in one place. The same variables are needed in CI, on the server that runs the app, and in cloud development environments such as GitHub Codespaces, Codex cloud in ChatGPT and Claude Code on the web. With dotvault, every one of those places gets its values the same way: dotvault pull, one command. Install, login and init happen once per place. After that it is pull, or run if you want no .env file.

Any environment that has Node.js and can reach the internet over HTTPS runs the same steps. The terminal screens in this part come from a fresh node:20 Docker container with nothing carried over from my own machine. This is part 2 of 12, run on October 18, 2026 against the production console at app.dotvault.io and the latest published CLI (0.15.7). Every step has its screen.

The short version

  • One command per place: dotvault pull. Install, login and init are once per place. If you commit the project-config.json that init writes, a fresh clone does not even need init.
  • Fix a value once, in the console. Every place picks it up on its next pull. With run, the next start already uses it.
  • Node.js plus outbound HTTPS is all it needs. This part was done in a fresh Linux container with a keychain (gnome-keyring and libsecret) added. Where there is no OS keychain, the CLI stores the token in a mode-600 file instead.
  • dotvault pull rewrites one marked block inside .env and leaves alone your own lines for keys dotvault does not hold. The file is written with mode 600, so only your user can read it.
  • dotvault run -- <command> skips the .env. The values from this part go into that one process without being written to a .env.
  • Places where no human logs in (CI, servers, AI agents working on their own) still run the same dotvault pull or run. The only difference is a service token instead of a login. Parts 7 and 8.

Where the same .env has to exist

The values live in one dotvault project. Only the way each place receives them differs.

Place Example How it gets the values
Your machine Mac, Windows, Linux Log in, then pull or run (this part)
Cloud dev environment with a human at the terminal GitHub Codespaces Exactly as on your machine (this part)
Cloud dev environment where an AI agent works on its own Codex cloud in ChatGPT, Claude Code on the web Service token, then the same pull or run (issuing and passing the token: parts 7 and 8)
CI/CD GitHub Actions and the like Service token, then the same pull or run (part 7)
Server runtime The server or container that runs the app Service token, then the same pull or run (issuing and passing the token: part 7)

Once per place, and every time after

Command When What it does
npm i -g @earthlink/dotvault Once per place Installs the CLI
dotvault login Once per place (again only when the refresh token expires; see step 2) Logs in with email and password
dotvault init Once per project folder (not needed in a clone once committed) Binds the folder to a project
dotvault pull / dotvault run -- <command> Every time you need the values Writes the .env / starts a command with the values

Creating the project and its keys in the console is also once per project. The rest of this part walks through the first time, in order.

Before you read on

  • Who this is for. Developers, freelancers and small teams who are still keeping the same .env in several places by hand. You do not need to have read part 1 to finish this one.
  • Date and environment. Screens are from October 18, 2026: the production console and CLI 0.15.7, the latest that day. npm i -g now installs 0.15.8; on October 23 I ran the same steps on 0.15.8, and the differences are the version number, the marker line written into .env (# BEGIN: dotvault (managed by dotvault)), the wording in brackets of the network error, and that a hand-written line for a key pull also writes is now commented out (see step 5), within what the steps of this part show (key and file counts are higher now because later parts add keys, files and Global Keys). The terminal is a Linux container (Docker node:20) with no earlier configuration and a keychain (gnome-keyring and libsecret) added. On macOS the commands are the same (the screens in this part were not taken on macOS; the first login may show a dialog asking to allow Keychain access).
  • Terminal screens are recomposed. Raw terminal screenshots come out too small to read, so the terminal figures reproduce the actual output verbatim in a cleaner frame. The raw output is kept as is. Exit codes, recorded separately, are shown as an echo $? line.
  • Demo account. The email address, project name and values in the screens were created for this series. None of the values are real.
  • Vocabulary. "Secret" means any value that must not leak: API keys, passwords, connection strings. A .env file is those secrets as KEY=VALUE lines. Part 1 has the full glossary.

1. Install (once per place)

Node.js 20 or later is the only requirement, on your machine or in a cloud dev environment's terminal.

npm i -g @earthlink/dotvault
dotvault --version

Terminal (recomposed, October 18, 2026):  raw `npm i -g @earthlink/dotvault` endraw  in a Node 20 container prints one npm deprecation warning about a dependency, then

npm prints one deprecation warning for a dependency. The install still completes. If dotvault --version prints a version number, you are ready.

2. Log in (once per place)

dotvault login asks for Email, then Password. The password is not echoed.

dotvault login
dotvault whoami

Terminal (recomposed, October 18, 2026):  raw `dotvault login` endraw  prompts for Email and Password and ends with . Token expires in 3600s. Refresh token saved."; `dotvault whoami` prints the email, the token expiry and "org: org_personal_… Personal (personal, org_admin)"."/>

The token goes into the OS keychain (Keychain on macOS), not into a plain-text file. "Token expires in 3600s" sounds short, but a refresh token is saved next to it, so you are not logging in every hour. The refresh token lasts 30 days; when it runs out, run dotvault login again.

dotvault whoami shows your email and the organisation you are in. At this point a Personal organisation already exists for you; it was created on your first login. Nobody had to set it up.

3. Create a project and three keys in the console (once per project)

The contents of the .env are prepared in the browser console at app.dotvault.io, with the same email and password. In a Personal organisation the sidebar shows eight items under a PERSONAL heading. The team features (Teams, My Organizations) are not there.

Console sidebar in a Personal organisation (English UI): Dashboard, Members, Projects, Global Keys, Service Tokens, Audit Log, Help and User Settings under the PERSONAL heading; no Teams, no My Organizations.

Open Projects and press New project. The modal asks for one thing, a name: lowercase letters, digits, hyphens and underscores, starting with a letter or digit. I used demo-app. Project names are unique across dotvault, so demo-app is taken; pick your own.

Create project modal (English UI, October 18, 2026): one Project name field, the rule

After Create, the list shows demo-app with three environments already attached: development, staging, production. Part 3 is about those. This part only uses development.

Projects list (English UI): the demo-app row with development, staging and production, plus Settings and Access links; an Active only filter and

Open demo-app. The Keys tab has development selected and no keys yet, so it says "No keys in development yet." The Selected key panel on the right says "Click a key on the left to inspect."

demo-app Keys tab (English UI, October 18, 2026): environment switch (development, staging, production, Common (_shared)), a Filter keys box, + Add key / + Add file / ↑ Upload buttons, the empty state

Press + Add key and an inline row appears with Key name and Value. Fill both, press Add. Three times for DATABASE_URL, API_BASE_URL and SMTP_PASSWORD.

Keys tab after pressing + Add key (English UI): an inline row with Key name and Value filled with SMTP_PASSWORD and a demo value, Add and Cancel below it, and the earlier DATABASE_URL row underneath.

Click a key name and the Selected key panel shows its path (development/env/DATABASE_URL), a description field, a reveal button, delete, and a button that moves the key to Common, a shared place for keys that every environment can use. Common is covered in part 3. Values are not shown in the list. They appear only when you press the reveal button. The button says "audit-logged"; what the audit record actually holds is checked in part 10.

Keys tab with DATABASE_URL selected (English UI, October 18, 2026): three rows API_BASE_URL, DATABASE_URL, SMTP_PASSWORD, each with a lock icon and an updated timestamp; the Selected key panel shows development/env/DATABASE_URL, Description with Save description, Reveal value (audit-logged), Delete and ⬆ Promote to Common (_shared).

That is all the console work. When a value changes later, this is where you change it. Back to the terminal.

4. Bind the folder to the project (init, once)

In the project folder, dotvault init writes one file, project-config.json. The project name defaults to the folder name; dotvault init --name <name> overrides it.

cd demo-app
dotvault init
cat project-config.json

Terminal (recomposed, October 18, 2026):  raw `dotvault init` endraw  prints

There are no secrets in this file: the project name, the API URL, the list of files to write, the default environment. Commit it. Any clone, in CI or in a cloud dev environment, can then pull without running init.

5. Pull the .env (every time)

dotvault pull runs three stages on one progress bar, authenticating, fetching, writing, and finishes with the number of keys written.

Before pulling, I put a few hand-written lines in .env (a comment, PORT and DEBUG) to show what happens to them.

dotvault pull
cat .env
ls -l .env

Terminal (recomposed, October 18, 2026):  raw `cat .env` endraw  shows three hand-written lines (a comment, PORT=3000, DEBUG=app:*);  raw `dotvault pull` endraw  shows the progress bar, then

Three things to notice.

  1. Your lines survive. dotvault only writes the block between # BEGIN: and # END:. The next pull replaces that block. That is what "Markers preserved." means. On 0.15.8, the current version, a line outside the block for a key that pull also writes (say a hand-kept DATABASE_URL=) is turned into a comment starting with # dotvault: moved into the managed block below:, and pull prints a warning. Nothing is deleted; the value inside the block is the one that applies. When you move a hand-kept .env to dotvault, that warning tells you which keys overlapped.
  2. The file is mode 600. -rw------- means your user can read and write it and no other user on the machine can read it.
  3. The keys added in this part come out sorted by name, not in the order you added them in the console.

After you change a value in the console, the same dotvault pull in any place replaces the marked block with the current values.

6. Run without a .env (run, every time)

If you would rather not have a .env on disk, dotvault run -- <command> puts the variables from this part into that one process's environment without writing a .env. One exception: if the project holds whole-file secrets (such as .npmrc, covered in part 5), run writes those files to disk while the command runs. They are removed when the command ends normally, but can be left behind if you stop dotvault itself, for example with Ctrl-C. Part 5 covers this.

dotvault run -- printenv DATABASE_URL
dotvault run -- sh -c 'echo "$API_BASE_URL"'

Terminal (recomposed, October 18, 2026): both  raw `dotvault run -- printenv DATABASE_URL` endraw  and  raw `dotvault run -- sh -c 'echo

When to use which:

dotvault pull dotvault run -- <command>
.env on disk Yes (the marked block only) No
Who sees the values Anything that reads the file That one process
Fits Tools and frameworks that expect a .env, start scripts written by other people Local development (dotvault run -- npm run dev), CI, anywhere you do not want a plain-text .env on disk (whole-file secrets: part 5)
After a value changes Pull again The next start uses the new value

For local development, use run. If there is no plain-text .env, it cannot be committed by accident and it does not end up in a backup.

It works without init too

In a folder with no project-config.json, pull and run still work if you name the project. A bare dotvault list shows the projects you can read.

dotvault list demo-app
dotvault pull demo-app

Terminal (recomposed, October 18, 2026), in a folder that is not a project:  raw `dotvault list demo-app` endraw  prints project=demo-app and a table with env, file, keys and last_modified (development, .env, 3, a timestamp);  raw `dotvault pull demo-app` endraw  prints

Putting the project name straight after the command (dotvault pull demo-app) and --project demo-app mean the same thing. init is only for pinning a folder to a project.

Reading a failure

A failure prints ✖, a code in capitals, and sets a fixed exit code (echo $?). Scripts can branch on the exit code. The table lists the causes seen in this part and what to check first; the same code can have other causes too.

Terminal (recomposed, October 18, 2026) with five failures:  raw `dotvault pull` endraw  in a folder without config → ✖ VALIDATION_ERROR (exit 6); staging named but holding no keys → ✖ PROJECT_NOT_FOUND (5);  raw `Demo-App` endraw  with capitals → ✖ BAD_PROJECT (1); API URL pointed at an unreachable address → ✖ NETWORK_ERROR (2); pull after logout → ✖ AUTH_REQUIRED (3).

code exit What happened What to do
AUTH_REQUIRED 3 Not logged in dotvault login
PERMISSION_DENIED 4 No permission on that project or environment, or no project by that name First check the project name for typos: a project name that does not exist also returns this code. If the name is right, ask an org admin to grant access in the console. A service token also gets it when it reads an environment or project it was not allowed (part 7). Permissions are covered in part 9
PROJECT_NOT_FOUND 5 No secrets for that project and environment (here: staging, which had no keys yet) Check your project's name with dotvault list, and in the console whether that environment has keys
VALIDATION_ERROR 6 No project-config.json, or something missing from the command Name the project, or run dotvault init in that folder
NETWORK_ERROR 2 The API URL cannot be reached Check the connection and apiUrl in project-config.json
BAD_PROJECT / BAD_ENV 1 Project name in the wrong format (capitals), or an environment the project does not have Use a lowercase name; use development, staging, production, or an environment you add in part 3

PROJECT_NOT_FOUND also appears when the project exists but that environment has no keys at all. The second failure in the screen is exactly that: staging, with nothing in it yet.

Same steps on Linux and in containers without a keychain

Where the OS keychain cannot be used (Linux without libsecret, or a headless container where libsecret is installed but no keychain service is running), the CLI prints a two-line notice and stores the token in ~/.config/dotvault/credentials.json with mode 600. The commands and the behaviour are the same. The screen below is the same container run without its keychain.

Terminal (recomposed, October 18, 2026):  raw `dotvault whoami` endraw  in the same Linux container, run outside its keychain service (no D-Bus session), prints

Appendix: your account

Forgotten password

From "Forgot your password?" on the login screen, enter your email to receive a confirmation code, then enter the code and the new password on the next screen. Passwords need at least 12 characters, with upper and lower case, a digit and a symbol. The form says 8, but the server rule, checked on October 23, 2026, is 12.

/forgot-password (English UI, October 18, 2026):

/forgot-password/confirm (English UI, October 18, 2026):

Display language

User Settings in the sidebar has a Language select. Choosing one saves immediately and shows "Saved." The setting lives in the browser, not on the account, so another browser starts from its own default.

User Settings (English UI, October 18, 2026): the note

Logging out

dotvault logout removes the stored token of the account currently in use from this machine (the keychain, or the file where there is no keychain). If no other account is logged in on this machine, dotvault whoami then says "Not logged in." If you also logged in with another account, that one is used after logout, so log out of it as well.

Terminal (recomposed, October 18, 2026):  raw `dotvault logout` endraw  prints ."; `dotvault whoami` prints "Not logged in." with exit code 3."/>

Not in this part

Registering and removing multi-factor authentication will be added to this part's appendix once the console has those screens. Switching to a team organisation after an invitation is covered, with its screens, in part 9.

Next

Part 3: "Three environments plus one shared layer, out of the box: how a dotvault project is shaped." The three environments that came with the project, the Common layer, comparing environments, and archiving and deleting a project, one screen at a time.


dotvault stores the secrets in your .env and config files server-side and hands them to any authorised developer, CI job or AI agent with a single command (https://dotvault.io). It will be released free of charge when this series ends, and the steps in these articles are the steps you will use on day one.

If you find this useful, please like and follow.

Our products are listed at https://www.eln.ne.jp/products


EarthLink Network builds its own products to run the whole company on AI — each one born from a need along the way. See the full index of what we build:

→ The 18 products EarthLink Network builds in-house

For more about the company and each product, visit www.eln.ne.jp.

來源:DEV Community · dev.to