0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

dotenvxを使用した環境変数管理

Posted at

dotenvxとは

  • セキュリティ
  • チームでの共有
  • デプロイワークフローとの統合

といったより高度な環境変数管理の課題を解決することを目指しているツールになります

セキュリティ

暗号化には公開鍵暗号方式のSecp256k1(ビットコインで採用されていることで有名)を使用して強固な暗号化を行っています

チームとの共有

.env自体を暗号化出来るためGitのバージョン管理に載せることができます
そのため新しくAPI Keyなどを追加したとしても開発メンバーへの共有がGitのバージョン管理だけで行えます

デプロイワークフローとの統合

CI/CDパイプラインやクラウド環境へのデプロイ時に暗号化されて環境変数が渡るためリスクを減らして運用が出来ます

例としてVercelでdotenvxを使用する際のDocsです

実際に試してみる

環境はHonoで行っていきます
構築済みを体にして進めていきます

.env

仮の環境変数を設定していきます

.env
# アプリケーション設定
NODE_ENV=development
PORT=3000

dotenvxインストール

dotenvxをインストールしていきます

zsh
npm install @dotenvx/dotenvx --save

.envを暗号化

zsh
dotenvx encrypt -f .env

実行すると下記内容が表示されて.env.keyが生成されているはずです
嬉しいことに.envに記載してあったコメントはそのままになってくれます

.env.keyは秘密鍵なので管理には注意してください

zsh
✔ 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を使用しない形で実装します

app.ts
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の内容が復号化されていないためですね

zsh
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行コードを追加してあげます

app.ts
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,
});

追加出来たら実行してみましょう

zsh
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コマンドを叩いても問題なく返り値があります

zsh
curl http://localhost:3000/health
{"status":"ok","timestamp":"2025-08-01T14:31:03.124Z","environment":"development"}%  

環境変数を追加しても動作するか確認していきます

zsh
dotenvx set APP_NAME TestApp

下記メッセージが表示されれば追加成功です

zsh
✔ set APP_NAME with encryption (.env)
app.ts
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で実行してみてコマンドで追加した内容が表示されていれば正常に動作しています

zsh
curl http://localhost:3000/name
zsh
Hello, TestApp!

まとめ

dotenvxはセキュアでありながら開発体験を良くしてくれるツールになるかと思います
GUIや1Passwordを開かなくても.envの変更・共有・反映ができるためコマンドライン中心のチームやCLI好きな開発者にとってはかなり快適になるかと感じました
dotenvxを開発環境に導入することを検討しても良いかもしれないです

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?