react / next 로 개발을 하다가 보면, 환경변수를 사용하여 개발해야하는 상황이 생기고, 그때의 접근은 process.env.ENVIRONEMNT_VALUE 로 접근한다. 하지만, 이러한 방식의 접근은 다음의 두가지 불편한 점이 있다.
.env 파일에 해당 값이 없을 경우, 원치 않는 상황에서 에러를 발생시킨다.이러한 상황에 도움을 줄 라이브러리를 발견했다. ts 환경에서 안전하게 환경변수에 접근할 수 있도록 해주면서, 해당 환경변수 값이 존재하지 않을 시 보다 안정된 에러를 발생시켜주는 유용한 친구인 @t3-oss/env-nextjs 이다.
이 라이브러리는 스키마 정의 라이브러리인 'zod' 와 결합이 되어, 타입 검증과 함께 사용되며, 잘 활용하면 환경 변수의 유형을 정의하고, 유효성을 검사하여 오류나 누락된 값에 대한 방어 코드를 작성할 수 있다.
또한 이외에도 유용한 장점들을 갖고 있다.
zod 스키마를 통해 각 환경 변수의 타입을 엄격히 검사한다.
어떤 변수는 클라이언트에서, 어떤 변수는 서버에서만 접근 가능하도록 구분하여 보안을 강화한다.
필수 환경 변수가 없거나 타입이 잘못된 경우, 빌드 타임에 오류를 발생시켜 문제를 조기에 발견할 수 있다.
개발, 스테이징, 프로덕션 환경에 맞춘 설정이 가능하다.
환경 변수를 정의하고 검증할 env.ts 파일을 생성하며 다음과 같이 예시를 들 수 있다.
client와 server 객체를 사용하여 환경 변수를 정의한다. client에 정의된 변수는 클라이언트에서 접근할 수 있으며, server 변수는 서버에서만 접근 가능하다.
import { createEnv } from '@t3-oss/env-nextjs';
import { z } from 'zod';
export const env = createEnv({
client: {
NEXT_PUBLIC_API_URL: z.string().url(),
NEXT_PUBLIC_ANALYTICS_ID: z.string(),
},
server: {
DATABASE_URL: z.string().url(),
SECRET_KEY: z.string(),
},
runtimeEnv: process.env, // 런타임 환경 변수를 process.env에서 가져온다.
});
이렇게 정의하고 나면 아래와 같이 안전하게 타입과 같이 환경변수에 접근이 가능하다.
env.NEXT_PUBLIC_ANALYTICS_ID
env.DATABASE_URL
env.SECRET_KEY
위에서 설정한 env세팅은, client와 server env를 하나의 바구니에서 정의하고 관리하였다. 하지만, 더 나아가 client env 세팅 따로, server env 세팅도 따로 아예 독립적으로 분리시킬 수도 있다.
// clientEnv.ts
import { createEnv } from '@t3-oss/env-nextjs';
import { z } from 'zod';
export const clientEnv = createEnv({
client: {
NEXT_PUBLIC_API_URL: z.string().url(),
NEXT_PUBLIC_ANALYTICS_ID: z.string(),
},
runtimeEnv: {
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
NEXT_PUBLIC_ANALYTICS_ID: process.env.NEXT_PUBLIC_ANALYTICS_ID,
},
});
// serverEnv.ts
import { createEnv } from '@t3-oss/env-nextjs';
import { z } from 'zod';
export const serverEnv = createEnv({
server: {
DATABASE_URL: z.string().url(),
SECRET_KEY: z.string(),
},
runtimeEnv: {
DATABASE_URL: process.env.DATABASE_URL,
SECRET_KEY: process.env.SECRET_KEY,
},
});
이러한 방식들의 차이점을 정리해보자면,
하나의 env에서 관리를 한다면 단순하고 접근하기 쉽다는 점이 있지만, 관리해야하는 환경 변수가 많아지면 가독성이 떨어지고, 또 클라이언트 측 코드에서 서버 전용 환경변수가 개발자의 실수로 노출될 가능성도 생긴다.
env 세팅을 client 와 server로 분리하면 보안을 한층 더 강화시킬 수 있으며 관리하는 환경변수를 더 직관적으로 구분짓기 쉽다는 장점이 생긴다.
따라서, 독립적으로 분리하여 관리하는 방식이 보안과 유지보수 측면에서 더 유리한 경우가 많다고 생각한다. 다만 요구사항과 규모에 따라 적절한 방법은 다를 수 있는 점을 인지해야한다.