dotenvxとは
- セキュリティ
- チームでの共有
- デプロイワークフローとの統合
といったより高度な環境変数管理の課題を解決することを目指しているツールになります
セキュリティ
暗号化には公開鍵暗号方式のSecp256k1(ビットコインで採用されていることで有名)
を使用して強固な暗号化を行っています
チームとの共有
.env自体を暗号化出来るためGitのバージョン管理に載せることができます
そのため新しくAPI Keyなどを追加したとしても開発メンバーへの共有がGitのバージョン管理だけで行えます
デプロイワークフローとの統合
CI/CDパイプラインやクラウド環境へのデプロイ時に暗号化されて環境変数が渡るためリスクを減らして運用が出来ます
例としてVercelでdotenvxを使用する際のDocsです
実際に試してみる
環境はHonoで行っていきます
構築済みを体にして進めていきます
.env
仮の環境変数を設定していきます
# アプリケーション設定
NODE_ENV=development
PORT=3000
dotenvxインストール
dotenvxをインストールしていきます
npm install @dotenvx/dotenvx --save
.envを暗号化
dotenvx encrypt -f .env
実行すると下記内容が表示されて.env.key
が生成されているはずです
嬉しいことに.envに記載してあったコメントはそのままになってくれます
.env.key
は秘密鍵なので管理には注意してください
✔ encrypted (.env)
✔ key added to .env.keys (DOTENV_PRIVATE_KEY)
⮕ next run [dotenvx ext gitignore --pattern .env.keys] to gitignore .env.keys
⮕ next run [DOTENV_PRIVATE_KEY='4baf732f64d981866e1cee15576407c34e38d854ed4f66f5b202a28e8bb5fc4b' dotenvx run -- yourcommand] to test decryption locall
実行
まずはdotenvxを使用しない形で実装します
import { serve } from "@hono/node-server";
import { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => {
return c.text("Hello Hono! 🔥");
});
app.get("/health", (c) => {
return c.json({
status: "ok",
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV,
});
});
app.get("/api/users", (c) => {
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" },
];
return c.json(users);
});
app.get("/api/users/:id", (c) => {
const id = c.req.param("id");
const user = { id: Number(id), name: `User ${id}` };
return c.json(user);
});
const port = Number(process.env.PORT);
console.log(`Server is running on http://localhost:${port}`);
serve({
fetch: app.fetch,
port,
});
実際に実行すると当然エラーが発生します
.envの内容が復号化されていないためですね
npm run dev
> hono-dotenvx@1.0.0 dev
> tsx watch src/index.ts
Server is running on http://localhost:NaN
node:net:2058
validatePort(options.port, 'options.port');
^
RangeError [ERR_SOCKET_BAD_PORT]: options.port should be >= 0 and < 65536. Received type number (NaN).
at Server.listen (node:net:2058:5)
at serve (file:///Users/roll1226/personalDevelopment/hono-dotenvx/node_modules/@hono/node-server/dist/index.mjs:557:10)
at <anonymous> (/Users/roll1226/personalDevelopment/hono-dotenvx/src/index.ts:43:1)
at ModuleJob.run (node:internal/modules/esm/module_job:268:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:543:26)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:116:5) {
code: 'ERR_SOCKET_BAD_PORT'
}
次に.envが復号化されるために1行コードを追加してあげます
import { serve } from "@hono/node-server";
import { Hono } from "hono";
+ import "@dotenvx/dotenvx/config";
const app = new Hono();
app.get("/", (c) => {
return c.text("Hello Hono! 🔥");
});
app.get("/health", (c) => {
return c.json({
status: "ok",
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV,
});
});
app.get("/api/users", (c) => {
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" },
];
return c.json(users);
});
app.get("/api/users/:id", (c) => {
const id = c.req.param("id");
const user = { id: Number(id), name: `User ${id}` };
return c.json(user);
});
const port = Number(process.env.PORT);
console.log(`Server is running on http://localhost:${port}`);
serve({
fetch: app.fetch,
port,
});
追加出来たら実行してみましょう
npm run dev
> hono-dotenvx@1.0.0 dev
> tsx watch src/index.ts
[dotenvx@1.48.4] injecting env (7) from .env
Server is running on http://localhost:3000
問題なく復号化されて正常に動作しています
curlコマンドを叩いても問題なく返り値があります
curl http://localhost:3000/health
{"status":"ok","timestamp":"2025-08-01T14:31:03.124Z","environment":"development"}%
環境変数を追加しても動作するか確認していきます
dotenvx set APP_NAME TestApp
下記メッセージが表示されれば追加成功です
✔ set APP_NAME with encryption (.env)
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import "@dotenvx/dotenvx/config";
const app = new Hono();
app.get("/", (c) => {
return c.text("Hello Hono! 🔥");
});
app.get("/health", (c) => {
return c.json({
status: "ok",
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV,
});
});
app.get("/api/users", (c) => {
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" },
];
return c.json(users);
});
app.get("/api/users/:id", (c) => {
const id = c.req.param("id");
const user = { id: Number(id), name: `User ${id}` };
return c.json(user);
});
+ app.get("/name", (c) => {
+ const appName = process.env.APP_NAME;
+ return c.text(`Hello, ${appName}!`);
+ });
const port = Number(process.env.PORT);
console.log(`Server is running on http://localhost:${port}`);
serve({
fetch: app.fetch,
port,
});
curlで実行してみてコマンドで追加した内容が表示されていれば正常に動作しています
curl http://localhost:3000/name
Hello, TestApp!
まとめ
dotenvxはセキュアでありながら開発体験を良くしてくれるツールになるかと思います
GUIや1Passwordを開かなくても.env
の変更・共有・反映ができるためコマンドライン中心のチームやCLI好きな開発者にとってはかなり快適になるかと感じました
dotenvxを開発環境に導入することを検討しても良いかもしれないです