Code:L 프로젝트를 진행하면서, 개발 서버와 운영 서버를 나눠서 관리하게 됐어요.
서버 환경이 나뉘다 보니 API 주소뿐만 아니라 Firebase 설정 파일도 환경마다 따로 관리해야 했어요.
처음 접했을 때는 Scheme, Configuration, xcconfig가 각각 뭘 하는 건지 잘 구분이 안 됐어요.
개념들이 서로 얽혀 있어서 하나를 찾아보면 또 모르는 용어가 나오고, 결국 직접 적용해보면서 하나씩 정리하게 됐어요.
이 글에서는 Code:L에서 실제로 사용한 구성을 바탕으로, Scheme · Configuration · xcconfig로 빌드 환경을 구성하는 방법과 환경마다 달라지는 리소스(Firebase 설정 파일, 앱 아이콘 등)를 관리하는 방법까지 하나씩 소개해보려고 해요.
전체 흐름 먼저 보기
개념마다 따로 보면 헷갈리는데, 흐름으로 한 번에 보면 생각보다 단순해요.
개발자가 Scheme 선택
↓
Scheme이 Configuration 결정 (Debug / Staging / Release ...)
↓
Configuration이 xcconfig 파일 참조
↓
xcconfig 값이 Build Settings + Info.plist에 주입
↓
Build Phase가 환경에 맞는 Firebase plist 포함
↓
앱 빌드 완료
이 흐름에서 등장하는 개념이 크게 네 가지예요. 하나씩 살펴볼게요.
Configuration — "어떤 환경으로 빌드할 거야?"
Configuration은 빌드 환경 자체를 정의하는 개념이에요.
Xcode가 기본으로 제공하는 건 Debug와 Release 두 가지예요.
그런데 Code:L처럼 개발 서버와 운영 서버를 나눠서 관리하는 경우엔 Configuration을 직접 추가하게 돼요.
Project > Info 탭에 들어가면 현재 등록된 Configuration 목록을 확인하고 새로 추가할 수 있어요.

Code:L에서는 이렇게 네 가지 Configuration을 사용했어요.
Debug # 운영 서버 / 개발 빌드 (디버깅 가능, 시뮬레이터·기기 직접 실행)
DebugStaging # 스테이징 서버 / 개발 빌드 (디버깅 가능, 시뮬레이터·기기 직접 실행)
Release # 운영 서버 / 배포 빌드 (App Store 제출용)
ReleaseStaging # 스테이징 서버 / 배포 빌드 (TestFlight 등 스테이징 배포용)
왜 네 가지나 필요할까요?
이름을 보면 두 가지 축이 보여요.
Debug 빌드Release 빌드
| 운영 서버 | Debug | Release |
| 개발 서버 | DebugStaging | ReleaseStaging |
각 조합이 필요한 이유가 달라요.
- Debug — 운영에서만 재현되는 버그를 디버거 붙여서 직접 파볼 때 필요해요.
- DebugStaging — 일상적인 개발. 개발 서버에 붙어서 기능 만들고 테스트하는, 가장 자주 쓰는 환경이에요.
- Release — App Store 제출용. 최적화된 빌드로 실제 유저 환경과 동일해요.
- ReleaseStaging — TestFlight로 팀원/QA에게 배포할 때 써요. 디버그 빌드는 느리고 불안정할 수 있으니, 릴리즈 빌드 품질로 개발 서버에 붙어서 테스트하는 거예요.
결국 "어떤 서버에 붙을지" 와 "어떤 빌드 품질로 만들지" 를 독립적으로 조절하고 싶어서 네 가지가 된 거예요.
Configuration에 xcconfig 파일 연결하기
Configuration을 만든 것만으로는 아직 아무 값도 없어요.
여기에 xcconfig 파일을 연결해줘야 실제 설정값이 주입돼요.
각 Configuration 항목 오른쪽 Based on Configuration File 컬럼에서, 연결할 xcconfig 파일을 선택할 수 있어요.
Code:L에서는 환경에 따라 xcconfig 파일을 나눠서 연결해뒀어요.
| Debug, Release | Secrets.xcconfig |
| DebugStaging, ReleaseStaging | SecretsStaging.xcconfig |

이렇게 하면 해당 Configuration으로 빌드할 때, xcconfig에 정의된 값들이 Build Settings에 자동으로 주입돼요.
Scheme — "어떤 Configuration을 쓸지 묶어놓은 것"
Scheme은 빌드 / 테스트 / 아카이브 각 동작마다 어떤 Configuration을 사용할지를 묶어놓은 설정이에요.
Scheme을 환경별로 여러 개 만들면, Scheme 선택 하나만으로 빌드 환경 전체를 바꿀 수 있어요.
CodeL (Scheme) → Debug / Release Configuration
CodeLStaging (Scheme) → DebugStaging / ReleaseStaging Configuration


팀원이 "개발 빌드로 확인해봐" 라고 하는 건, 결국 "CodeL Scheme으로 실행해봐" 와 같은 말이에요.
xcconfig — "설정값을 코드처럼 파일로 관리하기"
xcconfig는 Configuration에 들어갈 Key-Value 설정값을 파일로 관리하는 방식이에요.
Xcode의 Build Settings에 직접 입력해도 되긴 해요.
그런데 xcconfig를 쓰면 Git으로 변경 이력을 관리할 수 있고, 값들을 한눈에 보기도 훨씬 쉬워져요.

⚠️ CocoaPods를 함께 쓰는 경우, xcconfig 연결 방식에 주의가 필요해요.
CocoaPods도 내부적으로 xcconfig를 사용하기 때문에, 잘못 연결하면 충돌이 생길 수 있어요.
xcconfig 값을 Info.plist에서 사용하기
xcconfig에서 정의한 값은 Info.plist에서 $() 문법으로 참조할 수 있어요.
빌드 시점에 Xcode가 $(API_BASE_URL)을 xcconfig에 정의된 값으로 치환해줘요.
앱 코드에서는 Info.plist에서 이 값을 읽어서 사용하면 돼요.

정리하면 이런 관계예요.
| 언제 읽힘 | 빌드 타임 | 런타임 |
| 역할 | 값을 정의하고 주입하는 쪽 | 값을 받아서 앱에서 쓰는 쪽 |
xcconfig가 공급자, Info.plist가 소비자라고 이해하니까 훨씬 명확해졌어요.
환경마다 달라지는 리소스 관리하기
Firebase 설정 파일처럼 환경마다 달라지는 리소스를 분리하는 대표적인 방법은 두 가지가 있어요.
방법 1 — Build Phase Script
빌드 시점에 스크립트를 실행해서 환경에 맞는 파일로 교체하는 방식이에요.
Build Phase가 뭔지, 어떻게 활용하는지는 별도 포스팅에서 자세히 다룰 예정이에요.
방법 2 — Build Settings (EXCLUDED_SOURCE_FILE_NAMES)
Configuration에 따라 필요 없는 파일을 빌드 타임에 아예 제외하는 방식이에요.
스크립트 없이 설정만으로 동작하기 때문에 오류 걱정이 없어요.
Code:L에서는 방법 2를 선택했어요.
Firebase/Prod, Firebase/Staging 폴더에 각각 GoogleService-Info.plist를 두고, Configuration에 따라 필요 없는 쪽을 빌드 타임에 제외해요.

Configuration제외되는 파일번들에 포함되는 파일

각 빌드에 해당 환경의 파일 하나만 포함되기 때문에, Firebase 초기화 코드도 별도 분기 없이 단순하게 작성할 수 있어요.
개념 정리
개념역할비유
| Scheme | 어떤 환경으로 빌드할지 선택 | 리모컨 |
| Configuration | 환경 자체를 정의 (Dev / Staging / Prod) | 채널 |
| xcconfig | Configuration에 들어갈 값을 파일로 관리 | 채널 설정값 |
| Info.plist | 앱이 런타임에 읽는 설정 | 앱이 켜질 때 읽는 설명서 |
| Build Phase | 빌드 중 리소스 포함 / 스크립트 실행 | 빌드 자동화 도구 |
마치며
처음엔 그냥 "API 주소 두 개 관리하는 거잖아"라고 생각했는데, 막상 파고들어 보니 생각보다 많은 개념이 얽혀 있었어요.
그래도 흐름을 한 번 잡고 나면 생각보다 단순해요.
Scheme을 고르면 Configuration이 결정되고, Configuration이 xcconfig를 참조하고, xcconfig 값이 앱 전체에 주입되는 구조예요. 거기에 Firebase처럼 환경마다 달라지는 리소스는 Build Settings에서 빌드 타임에 걸러내면 되고요.
각 개념이 왜 존재하는지 이해하고 나니, 처음엔 복잡해 보이던 설정들이 오히려 꽤 깔끔하게 느껴졌어요.
환경 설정이 낯설어서 헤매고 있는 분들께 조금이라도 도움이 됐으면 해요.
'기타' 카테고리의 다른 글
| TCA QnA (0) | 2026.06.10 |
|---|---|
| Swift Concurrency QnA (0) | 2026.06.10 |
| TCA란? (0) | 2026.06.10 |
| GitHub 403 에러 (Permission denied) 해결 방법 (0) | 2025.04.04 |
| Git 잔디가 안심어짐 (0) | 2024.08.16 |