.env 파일 대신 Infisical을 쓰기로 한 이유
.env 파일을 직접 관리하던 방식에서 벗어나 Infisical로 환경변수 기준을 다시 세운 과정입니다. 로컬, dev 서버, GitHub Actions 배포 흐름을 정리하면서 겪은 시행착오와 goodtek이 선택한 운영 기준을 기록했습니다.
요즘 바이브코더 분들이 주변에도 엄청 많이 생기기 시작했습니다. 자신이 겪고 있는 문제를 해결하기 위해 아이디어를 생각하고 그 아이디어를 돌아가는 앱을 만드는 건 이제 누구나 할 수 있는 세상이 되었습니다.
하지만 그 앱이 실제 고객이 비용을 지불하고 사용하는 순간부터 무한 책임은 시작 됩니다. 사용자들도 이제 안정된 서비스가 보장되지 않으면 지불을 고민하기 시작했구요.
goodtek은 해당 관점에서 바닥 공사가 단단한 어플리케이션을 구축하는 방법을 공유합니다. 말만 하는게 아니라 실제로 구축하는 과정을 공유하면서 말입니다.
오늘은 바닥공사 중에도 아주 기초를 튼튼하게 해 주는 그런 내용입니다.
.env 파일을 만들 때마다 항상 같은 고민을 합니다.
이걸 로컬에만 둘까?
Git에는 당연히 올리면 안 되겠지?
배포할 때는 서버에 직접 넣을까, 아니면 GitHub Actions Secrets에 넣고 주입할까?
처음에는 별것 아닌 문제처럼 보입니다.
그냥 .gitignore에 .env를 추가하면 끝난 것 같거든요.
그런데 프로젝트를 계속 고치고, 배포하고, 다시 수정하다 보면 이 작은 파일 하나가 은근히 신경을 긁습니다.
민감 정보는 숨겨야 하고, 개발은 편해야 하고, 배포는 자동화되어야 하고, 문제가 생겼을 때 복구도 가능해야 합니다.
여기서 기준이 없으면 결국 이렇게 됩니다.
로컬에는 로컬대로 .env가 있고,
GitHub Actions에는 DEV_* 변수가 따로 있고,
서버에는 예전에 만들어 둔 .env가 남아 있습니다.
그리고 언젠가 한 번은 이런 생각을 하게 됩니다.
“지금 실제로 쓰이고 있는 환경변수는 어디 있는 거지?”
이번 TASK-010은 바로 그 찝찝함에서 시작했습니다.
큰 주제는 단순했습니다.
.env 파일 대신 Infisical을 사용하자.
하지만 실제로 해보니, 이건 단순히 도구를 바꾸는 작업이 아니었습니다.
환경변수를 관리하는 기준 자체를 다시 세우는 작업에 가까웠습니다.
그냥 동작하는 서비스 말고, 계속 고칠 수 있는 서비스
goodtek이 지금 만들고 있는 건 단순히 “오늘만 동작하면 되는 서비스”가 아닙니다.
계속 수정하고, 개선하고, 실험하고, 배포해야 합니다.
그 과정에서 프로젝트 코드나 배포 흐름이 쉽게 깨지지 않아야 합니다.
저는 이걸 요즘 조금 더 크게 보고 있습니다.
서비스의 기능만 만드는 게 아니라, 서비스를 계속 고칠 수 있는 라이프사이클을 만드는 것.
환경변수 관리는 그 라이프사이클의 꽤 중요한 부분입니다.
처음에는 .env 파일 하나만 잘 숨기면 된다고 생각하기 쉽습니다.
하지만 실제 운영에서는 질문이 더 많아집니다.
| 질문 | 대충 처리하면 생기는 문제 | 이번에 정한 방향 |
|---|---|---|
| 로컬 환경변수는 어디서 가져오나 | 사람마다 .env가 달라짐 | Infisical local |
| dev 서버 값은 누가 최신으로 관리하나 | 서버 .env가 오래됨 | Infisical dev에서 export |
| GitHub Actions 배포 변수는 어디에 두나 | GitHub Secrets와 앱 변수가 분리됨 | Infisical dev에서 OIDC 주입 |
| 긴급 상황에서는 어떻게 하나 | Infisical 장애 시 실행 불안 | local .env 폴백 유지 |
핵심은 “예쁜 구조”가 아니었습니다.
나중에 다시 봤을 때도 이해할 수 있고, 누가 봐도 어디가 기준인지 알 수 있는 구조가 필요했습니다.
그래서 이번 시점에서 민감 정보와 환경변수를 정석에 가깝게 관리하기로 했습니다.
왜 Infisical이었나
goodtek은 이미 별도로 설치형 Infisical을 구축해서 사용하고 있었습니다.
그래서 선택지는 자연스럽게 좁혀졌습니다.
새 서비스를 또 붙이기보다, 이미 운영 중인 Infisical을 goodtek-web 환경변수 관리의 기준으로 삼는 게 맞다고 판단했습니다.
Infisical은 쉽게 말하면 환경변수와 시크릿을 중앙에서 관리하고, 필요한 시점에 로컬·서버·CI/CD로 주입해주는 도구입니다.
기존에는 .env 파일이 각 환경에 흩어져 있었다면, Infisical을 쓰면 이런 식으로 흐름이 바뀝니다.
Infisical
├─ local
│ └─ 개발자 PC에서 pnpm dev 실행 시 주입
├─ dev
│ ├─ dev 서버 compose용 .env export
│ └─ GitHub Actions 배포 변수 주입
└─ prod
└─ 향후 프로덕션 배포용으로 준비
처음 계획에서는 local, dev-server, ci처럼 더 잘게 나누는 것도 고민했습니다.
그런데 실제로 보니 CI 자체는 비밀값이 거의 필요 없었습니다.
lint와 build는 굳이 시크릿 없이 돌아가는 편이 더 낫습니다.
반대로 dev 서버와 GitHub Actions 배포는 같은 dev 환경을 바라보는 게 자연스러웠습니다.
그래서 최종적으로는 이렇게 정리했습니다.
| Infisical 환경 | 용도 | 비고 |
|---|---|---|
local | 개발자 로컬 실행 | pnpm dev, pnpm dev:stack |
dev | dev 서버와 배포 | compose .env, GitHub Actions |
prod | 향후 운영 환경 | 이번 TASK 범위 밖 |
여기서 중요한 건 환경 이름 자체보다 각 환경의 책임을 분명히 나누는 것이었습니다.
환경변수 관리에서 제일 위험한 건 값이 없는 게 아니라, 기준이 여러 개인 상태입니다.
.env, GitHub Secrets, Infisical을 비교해보면

물론 Infisical만이 정답은 아닙니다.
각 방식마다 장단점이 있습니다.
저도 이번에 정리하면서 “우리가 왜 굳이 Infisical까지 써야 하지?”를 다시 생각해봤습니다.
| 방식 | 장점 | 단점 | 어울리는 상황 |
|---|---|---|---|
로컬 .env | 단순하고 빠름 | 사람마다 값이 달라짐, 공유 어려움 | 초기 실험, 개인 프로젝트 |
서버 .env | 배포 서버에서 바로 사용 가능 | 최신 값 추적 어려움, 수동 작업 증가 | 작은 단일 서버 |
| GitHub Secrets | Actions와 연동 쉬움 | 로컬·서버 변수와 분리됨 | CI/CD 중심 배포 |
| Infisical | 중앙 관리, 환경 분리, 주입 자동화 | 서비스 의존성 증가 | 지속적으로 개선하는 팀 프로젝트 |
예전 같으면 저는 그냥 .env로 버텼을 것 같습니다.
하지만 지금 goodtek은 빌드 로그를 남기면서 계속 프로젝트를 고치고 있습니다.
작은 수정이 반복되고, 배포도 반복됩니다.
이 상황에서는 지금 당장 편한 방식보다 다음 수정 때 덜 깨지는 방식이 더 중요했습니다.
구현 방향은 이렇게 잡았다

이번 작업의 목표는 단순했습니다.
루트 .env를 직접 관리하지 않고,
Infisical을 기준으로 로컬 실행과 dev 배포를 정리하는 것.
구현 방향은 크게 네 가지였습니다.
- 로컬 개발은
infisical run --env=local로 실행한다. - dev 서버는 배포 시 Infisical
dev에서.env를 export한다. - GitHub Actions는 OIDC로 Infisical에 접근한다.
.env.example은 실제 값이 아니라 스키마 문서로만 둔다.
실제 실행 흐름은 이런 느낌입니다.
개발자 PC
└─ pnpm dev
└─ infisical run --env=local
└─ local 시크릿 주입
GitHub Actions
└─ develop push
└─ OIDC로 Infisical 인증
└─ DEV_* 배포 변수 주입
dev 서버
└─ deploy-dev.sh
└─ infisical export --env=dev
└─ compose용 .env 재생성
로컬에서는 이런 식으로 감쌌습니다.
infisical run --env=local -- pnpm dev
물론 실제 package.json에서는 개발 명령어에 맞게 조금 더 정리했습니다.
중요한 건 로컬 .env를 직접 읽는 게 아니라, 실행 시점에 Infisical이 값을 주입한다는 점입니다.
설정하면서 바로 안 풀린 것들
이런 작업은 문서만 보면 꽤 매끈해 보입니다.
그런데 실제로 해보면 꼭 중간에 작은 턱들이 나옵니다.
이번에도 그랬습니다.
첫 번째는 환경 이름 문제였습니다.
처음에는 local, dev-server, ci로 나누려고 했습니다.
하지만 실제 운영 흐름을 보니 ci는 비밀값이 필요 없었고, dev-server와 GitHub Actions 배포는 같은 dev 환경으로 묶는 게 더 자연스러웠습니다.
그래서 중간에 구조를 바꿨습니다.
처음 정한 구조를 끝까지 밀고 가는 게 항상 좋은 건 아닙니다.
오히려 설정하면서 실제 흐름을 보고 바꾸는 게 더 안전할 때가 있습니다.
두 번째는 dev 서버에서 Infisical CLI를 설치하고 인증하는 과정이었습니다.
로컬에서는 브라우저 로그인으로 끝나지만, 서버는 다릅니다.
서버에서는 사람이 매번 로그인할 수 없으니 Machine Identity와 Universal Auth가 필요했습니다.
여기서도 한 번 막혔습니다.
권한 문제 때문에 서버의 web 사용자가 /etc/infisical/goodtek-web.env를 읽지 못했습니다.
결국 파일 소유권과 권한을 조정해야 했습니다.
/etc/infisical
└─ goodtek-web.env
├─ Universal Auth Client ID
├─ Universal Auth Client Secret
└─ Infisical API URL
여기서 배운 건 단순합니다.
시크릿 파일은 숨겨야 하지만, 실행하는 사용자는 읽을 수 있어야 합니다.
말로 쓰면 너무 당연한데, 서버에서 실제로 마주치면 은근히 자주 놓치는 부분입니다.
세 번째는 Machine Identity로 export할 때 projectId가 필요했던 점입니다.
사용자 로그인으로 CLI를 쓸 때는 .infisical.json이 꽤 자연스럽게 동작합니다.
그런데 서버의 Machine Identity 흐름에서는 export 시 projectId를 명시적으로 넘겨야 했습니다.
처음엔 .infisical.json이 있으니 당연히 읽겠지 싶었습니다.
아니었습니다.
여기서 또 한 번 멈췄습니다.
처음 구현에서는 .infisical.json에서 workspaceId를 grep으로 읽는 방식까지 갔습니다.
동작은 했지만, 솔직히 마음에 들지는 않았습니다.
JSON을 grep으로 파싱하는 건 “급한 불 끄기”에 가깝습니다.
그래서 이후에는 INFISICAL_PROJECT_ID를 환경 파일에 명시하는 방향으로 정리했습니다.
이 편이 서버 설정과 배포 스크립트 사이의 책임이 더 분명했습니다.
이번에 정리한 기준

시행착오를 거치면서 남은 기준은 꽤 명확했습니다.
- Infisical을 기준 저장소로 둔다.
- 로컬은
local, dev 서버와 배포는dev를 사용한다. .env.example은 값 저장소가 아니라 문서로만 사용한다.- dev 서버는 배포 때마다
.env를 재생성한다. - GitHub Actions는 OIDC로 필요한 값만 런타임에 받는다.
- 긴급 상황을 위해 local
.env폴백 가능성은 유지한다.
이 중에서 가장 마음에 드는 부분은 마지막입니다.
Infisical을 쓰면 분명히 Infisical이라는 서비스에 의존하게 됩니다.
이건 장점만 있는 선택이 아닙니다.
그래서 저는 이런 도구를 붙일 때 항상 백업 질문을 합니다.
“이 도구가 잠깐 죽어도, 최소한의 기동이나 복구는 가능한가?”
이번 구조에서는 필요한 경우 local .env로 긴급 기동할 수 있는 여지를 남겨두었습니다.
완전히 Infisical 없이는 아무것도 못 하는 구조로 만들지는 않았습니다.
그래서 결론은 이렇게 정리할 수 있습니다.
백업 프로세스를 마련해 둔 상태에서 개발과 배포를 더 편하게 해주는 도구라면, 안 쓸 이유가 없습니다.
Why not.
각자 환경은 다르지만, 중요한 포인트는 비슷하다
이번 시행착오는 goodtek의 환경에서 나온 것입니다.
설치형 Infisical을 이미 운영하고 있었고, dev 서버가 있었고, GitHub Actions로 배포를 붙이는 흐름이 있었습니다.
다른 팀이나 다른 프로젝트라면 세부 구현은 달라질 수 있습니다.
그래서 제가 겪은 과정 자체를 그대로 따라 할 필요는 없습니다.
대신 중요한 포인트는 비슷하다고 생각합니다.
| 체크 포인트 | 질문 |
|---|---|
| 기준 저장소 | 환경변수의 최종 기준은 어디인가? |
| 환경 분리 | local, dev, prod의 책임이 분명한가? |
| 실행 주체 | 로컬 사용자, GitHub Actions, 서버 사용자가 각각 어떻게 인증하는가? |
| 복구 가능성 | 중앙 시크릿 서비스 장애 시 최소 기동이 가능한가? |
| 문서화 | 새로 합류한 사람이 같은 방식으로 실행할 수 있는가? |
저는 이번 작업을 하면서 .env 파일을 없애는 것보다 더 중요한 걸 정리하게 됐습니다.
환경변수는 코드 밖에 있지만, 프로젝트 라이프사이클 안에 있다.
그래서 대충 관리하면 언젠가 코드보다 먼저 배포 흐름이 깨집니다.
이제 조금 덜 불안해졌다

이번 작업 이후로 환경변수 관리가 훨씬 수월해졌습니다.
로컬에서는 Infisical local을 보고 실행합니다.
dev 서버는 배포 때 Infisical dev에서 .env를 다시 만듭니다.
GitHub Actions는 OIDC로 필요한 배포 변수만 가져오도록 준비했습니다.
물론 아직 남은 일도 있습니다.
DEV_* 배포 키를 Infisical dev 환경에 추가하고, 실제 develop 배포까지 검증해야 합니다.
하지만 큰 방향은 잡혔습니다.
예전에는 .env를 만질 때마다 약간 불안했습니다.
“이 값이 최신인가?”
“서버에는 같은 값이 들어가 있나?”
“GitHub Actions에는 또 따로 넣어야 하나?”
이제는 질문이 조금 바뀌었습니다.
“Infisical의 어느 환경을 보고 있는가?”
이 질문 하나로 정리됩니다.
그 정도면 이번 작업은 충분히 의미가 있었습니다.
goodtek은 앞으로도 기능만 쌓는 게 아니라, 기능을 계속 고칠 수 있는 기반도 같이 다듬어가려고 합니다.
이번 .env → Infisical 전환은 그 기반을 정리한 작업 중 하나였습니다.
아마 다음에 비슷한 설정을 또 하게 되면, 이번보다 훨씬 덜 헤맬 겁니다.
그리고 이런 작은 기준들이 쌓이면, 프로젝트는 조금씩 더 단단해질 거라고 믿습니다.