TECH

React Native CLI to EXPO

DEC 25, 202513분

React Native(RN) 생태계에서 '자유도'는 오랫동안 가장 큰 장점으로 여겨져 왔다. 개발자가 네이티브 코드에 직접 접근할 수 있어 원하는 모든 커스터마이징이 가능하다는 점이 RN CLI의 핵심 가치였다. 하지만 프로젝트 규모가 커지고 운영 기간이 길어질수록 그 자유도는 점진적으로 유지보수 부담과 불확실성으로 전환되기 시작한다. RN CLI 환경에서 프로젝트를 장기간 운영하며 이런 구조적 한계를 반복적으로 경험했다. 버전 업데이트마다 마주하는 수동 작업의 반복, 네이티브 설정 관리의 복잡성, 그리고 예측하기 어려운 빌드 이슈들이 누적되면서 개발 생산성보다는 인프라 관리에 더 많은 시간을 할애하게 되었다. 이런 문제를 해결하기 위해 일반적인 흐름과는 반대인 CLI → Expo 전환을 결정했다. --- ## 1. 반복되는 '수동 재구축' RN CLI 환경에서의 버전 업데이트는 단순한 의존성 교체 작업이 아니다. 공식 문서에는 `npm install`과 몇 가지 설정 변경만으로 업데이트가 가능하다고 나와 있지만 현실적으로는 매번 반복되는 수동 재구축 과정에 가까웠다. ### 프로젝트 재생성의 반복 안정적인 업데이트를 보장하기 위한 한 가지 방법은 새로운 RN 버전으로 프로젝트를 새로 생성한 뒤 기존 비즈니스 로직과 라이브러리, 네이티브 설정(Native Configuration)을 하나씩 옮기는 것이다. 공식 업그레이드 가이드가 복잡하거나 여러 버전을 건너뛰어야 할 때 많은 개발팀이 실제로 이런 방식을 선택한다. 하지만 이 과정에서 놓치기 쉬운 설정들이 누적되면 업데이트 후 예상치 못한 동작이나 빌드 실패로 이어질 수 있다. 나도 여러 번 이런 방식을 택했고 매번 뭔가 놓치는 게 있었다. ### 네이티브 설정의 수작업 이전 `AppDelegate`, `build.gradle`, 권한 설정, 스키마 정의 등은 대부분 수동으로 이전해야 한다. 각 파일의 변경 사항을 비교하고 새로운 버전에 맞게 수정하는 과정에서 작은 누락이나 오타 하나가 원인을 알기 어려운 빌드 에러로 이어질 수 있다. 특히 Android의 경우 `build.gradle`의 의존성 버전 충돌이나 iOS의 경우 `Info.plist` 설정 누락 등은 디버깅에 많은 시간을 소모하게 만든다. 이런 걸 찾아내는 데 하루 종일 걸린 적도 있었다. ### 불확실성의 누적 공식 가이드를 정확히 따랐음에도 서드파티 라이브러리 충돌이나 네이티브 의존성(Native Dependency) 문제로 작업이 막히는 경우가 잦다. 각 라이브러리가 서로 다른 RN 버전을 요구하거나 네이티브 모듈이 최신 버전과 호환되지 않는 경우가 발생한다. 이런 상황에서는 업데이트를 중단하고 라이브러리 교체나 대안을 찾아야 하는데 이는 프로젝트의 기술 부채를 증가시키는 결과를 낳는다. 이런 과정은 단순히 엔지니어의 시간을 소모하는 것을 넘어 팀 전체가 업데이트를 기피하게 만드는 구조적 문제로 발전한다. 업데이트를 해야 한다는 걸 알면서도 그 과정이 너무 번거로워서 미루게 되는 것이다. 이건 기술적 문제라기보다는 프로세스의 문제다. 이런 '사람의 손'에 의존하는 프로세스를 '시스템'으로 바꾼 것이 바로 `prebuild`라고 생각했다. --- ## 2. 네이티브 코드는 재생성 가능한 산출물이다 Expo 전환을 결심하게 된 결정적인 계기는 `prebuild` 개념이었다. 이 개념을 접했을 때 네이티브 코드를 바라보는 관점이 근본적으로 바뀌어야 한다는 걸 깨달았다. ### 네이티브 코드의 재정의 기존 RN CLI 환경에서는 네이티브 코드(Native Code)를 "지속적으로 관리해야 할 소스"로 취급했다. `ios/`와 `android/` 폴더의 모든 파일을 버전 관리하고 변경 사항을 추적하고 충돌을 해결해야 했다. 하지만 `prebuild`는 네이티브 코드를 언제든 다시 생성 가능한 산출물(Native Artifact)로 취급한다. 소스가 아니라 빌드 결과물처럼 다루는 것이다. 이 접근법이 맞다고 생각한 이유는 재생성 가능성에 있다. 네이티브 코드가 `app.json`과 Config Plugin이라는 선언적(Declarative) 설정에서 자동으로 생성된다는 점이 핵심이다. 개발자는 네이티브 코드를 직접 수정하지 않고 설정 파일만 관리하면 된다. 이렇게 하면 네이티브 코드의 일관성이 보장되고 업데이트 시 항상 최신 템플릿으로 재생성할 수 있다. ### 선언적 설정 기반의 안정성 네이티브 변경 사항은 모두 `app.json`과 Config Plugin으로 선언된다. 예를 들어 카메라 권한이 필요하다면 `app.json`에 권한을 명시하고, 특정 네이티브 모듈을 추가해야 한다면 Config Plugin을 작성한다. Expo는 이를 기반으로 항상 동일하고 클린한 네이티브 코드를 생성한다. 또한 어떤 환경에서든 동일한 설정으로 동일한 네이티브 코드를 생성할 수 있어 개발 환경 간 일관성이 보장된다. ### 업데이트 프로세스의 변화 과거에는 며칠씩 소요되던 RN 업데이트 작업이 이제는 훨씬 짧은 시간 안에 안전하게 수행 가능해졌다. Expo SDK 버전만 올리고 `prebuild`를 실행하면 새로운 SDK에 맞는 네이티브 코드가 자동으로 생성된다. 설정 파일에 문제가 없다면 대부분의 경우 빌드가 성공한다. 네이티브 코드를 직접 관리할 필요가 없기 때문에 업데이트 과정에서 발생할 수 있는 수동 작업의 실수나 누락이 차단된다. 실제로 전환 후 업데이트 시간이 며칠에서 몇 시간으로 줄어들었다. ## 3. 운영 관점에서의 합리성 일반적으로는 Expo에서 시작해 CLI로 이동하는 흐름이 언급된다. 초기에는 Expo의 제약이 불편하게 느껴지고 CLI로 전환하면 더 많은 자유를 얻을 수 있다고 생각하기 때문이다. 하지만 장기 운영 관점에서는 오히려 CLI에서 Expo로의 전환이 더 강력한 안정성을 제공한다고 판단했다. ### Expo SDK라는 단일 기준점 RN CLI 환경에서는 여러 변수들의 호환성을 사람이 직접 판단해야 한다. React Native 버전, Android Gradle 버전, iOS 최소 버전, 각종 네이티브 라이브러리 버전 등이 모두 서로 호환되어야 하는데 이 조합의 수는 기하급수적으로 늘어난다. 각 라이브러리의 문서를 확인하고 GitHub 이슈를 검색하고 실제로 테스트해봐야만 안전한 업데이트 경로를 찾을 수 있다. 이런 과정을 반복하다 보니 체력적으로도 지치고 시간 낭비가 심했다. 반면 Expo는 SDK 버전을 중심으로 생태계를 정렬한다. 각 SDK 버전은 특정 RN 버전, 특정 네이티브 라이브러리 버전, 특정 빌드 도구 버전이 모두 호환되도록 검증되어 있다. 따라서 "SDK 50으로 업데이트하면 안전한가?"라는 질문에 대한 답은 "예"이다. 시스템 차원에서 보장되기 때문이다. 이 단일 기준점 덕분에 Expo 공식 라이브러리들도 SDK와 함께 테스트되고 버전 호환성이 보장된다. SDK가 기준이 되어 라이브러리까지 통제하는 구조다. 이 차이는 프로젝트 규모가 커질수록 더욱 명확해진다. 수십 개의 네이티브 라이브러리를 사용하는 프로젝트에서 CLI 환경의 호환성 문제를 해결하는 것은 점점 어려워진다. 하지만 Expo SDK는 이런 복잡성을 네이티브 레이어 추상화를 통해 해결한다. Expo 공식 라이브러리들은 전반적으로 품질과 문서화 수준이 높고 플랫폼 간 일관성이 우수하다. 또한 공식 문서가 상세하고 예제 코드가 풍부해 빠르게 학습하고 적용할 수 있다. 물론 일부 고급 제어가 부족한 영역이 있을 수 있지만 이런 경우에도 Config Plugin이나 Custom Native Module을 통해 확장할 수 있다. Expo는 제약을 강요하는 것이 아니라 표준화된 방식으로 확장할 수 있는 구조를 제공한다. ### Config Plugin을 통한 변경 이력의 자산화 RN CLI 환경에서 네이티브 커스터마이징은 주로 파일을 직접 수정하는 방식으로 이루어진다. `AppDelegate.swift`에 코드를 추가하거나 `build.gradle`에 설정을 넣는 식이다. 이런 변경 사항은 시간이 지나면 왜 추가했는지, 어떤 문제를 해결하기 위한 것인지 기억하기 어려워진다. 이게 문제였다. 몇 달 전에 추가한 설정이 왜 필요한지 모르겠어서 삭제했다가 다시 추가한 적도 있다. Expo의 Config Plugin은 이런 네이티브 커스터마이징을 코드로 관리한다. JavaScript나 TypeScript로 작성된 Plugin은 네이티브 코드를 어떻게 수정할지 명시적으로 정의한다. 네이티브 레이어의 변경(Modification)은 필연적이지만 그 방법을 직접 수정(Imperative)이 아닌 설정을 통한 플러그인 주입(Declarative) 방식으로 바꾼 것이다. 실제 네이티브 코드에 직접 수정하는 것이 아니라 별도로 분리해서 관리한다는 점이 핵심이다. 목적과 행동에 따라 Plugin으로 분리해두면 오류 발생 시 해당 Plugin만 격리하여 관리할 수 있다. 네이티브 코드에 수정 내역을 직접 기록(Hard-coding)하는 방식은 시간이 흐른 뒤 변경의 맥락을 파악하기 어렵게 만들지만 Config Plugin은 변경의 의도와 구현을 분리한다. 실제 네이티브 코드를 직접 수정하는 대신 별도의 플러그인으로 분리 관리한다는 점이 네이티브 변경 사항의 '가시성'을 확보해준다. 코드가 다소 생소할 수는 있으나 각 플러그인이 명확한 목적을 가진 독립된 모듈로 존재하므로 추적과 개선이 훨씬 가벼워진다. 변경 이력이 코드로 명확히 남아있어 문제 발생 시 원인 추적이 단순화되고 어떤 환경에서도 동일한 네이티브 상태를 재현할 수 있다. 또한 Config Plugin은 재사용 가능하다. 한 번 작성한 Plugin은 다른 프로젝트에서도 사용할 수 있고 커뮤니티에서 공유된 Plugin을 활용할 수도 있다. 이렇게 네이티브 커스터마이징의 지식이 코드로 축적되고 공유될 수 있게 된다. --- ## 4. 빌드와 배포 자동화 Expo는 개발 경험뿐 아니라 빌드·배포 영역에서도 성숙한 도구 체인을 제공한다. 이는 단순히 편의 기능을 넘어 운영의 예측 가능성과 재현성을 높이는 구조적 장점이다. 많은 개발자들이 Expo를 클라우드 빌드에 종속되는 것으로 오해한다. 하지만 실제로는 `eas build --local` 옵션을 통해 로컬 또는 사내 CI 환경을 그대로 활용할 수 있다. 기존 빌드 인프라를 유지하면서 Expo의 빌드 도구만 사용할 수 있다는 의미다. 로컬 빌드의 장점은 명확하다. 빌드 로그를 실시간으로 확인할 수 있고, 디버깅이 용이하며, 네트워크 지연 없이 빠르게 빌드할 수 있다. 또한 사내 보안 정책으로 인해 외부 클라우드 서비스를 사용할 수 없는 환경에서도 Expo를 활용할 수 있다. 하지만 더 중요한 건 빌드 환경 설정 자체다. RN CLI 환경에서는 각 개발자가 자신의 로컬 환경에 빌드 도구를 설치하고 설정해야 했다. Xcode, Android SDK, 각종 인증서와 키스토어 설정 등. 이 과정에서 환경 차이로 인한 빌드 실패가 빈번하게 발생했다. Expo는 이런 빌드 환경을 알아서 구성해준다. 환경 변수도 EAS에서 중앙 관리할 수 있어 각 개발자가 개별적으로 설정할 필요가 없다. EAS는 Fastlane과 같은 자동화 도구의 복잡성을 추상화하여 제공한다. EAS Build는 내부적으로 Fastlane 혹은 그와 유사한 빌드 파이프라인 아키텍처를 사용하며, 개발자가 복잡한 Ruby 스크립트 작성 없이도 수준 높은 자동화를 누리게 해준다. Fastlane을 직접 구축하면 동일한 자동화를 구현할 수 있지만 제대로 구축하는 데 드는 시간과 노력을 생각해보면 EAS가 제공하는 가치가 명확해진다. Fastlane 설정 파일 작성, CI/CD 파이프라인 구축, 환경 변수 관리 시스템 구축 등. 이런 작업들을 모두 해야 한다. 그리고 현실적으로 Fastlane을 제대로 구축해놓은 개발팀이 더 많을까? 대부분의 팀은 그냥 수동으로 배포하거나 부분적으로만 자동화되어 있을 것이다. EAS는 이런 모든 인프라를 이미 구축해놓고 제공한다. --- 이번 전환의 목적은 단순히 "편해 보이기 때문"이 아니다. 지속 가능하고 예측 가능한 개발 구조를 선택하기 위함이다. 프로젝트가 장기적으로 운영될수록 일관성과 안정성이 생산성보다 더 중요한 가치가 된다고 생각한다. RN CLI 환경에서는 네이티브 코드 관리, 버전 호환성 확인, 빌드 설정 유지보수 등에 많은 시간을 할애해야 했다. 이런 작업들은 개발의 핵심이 아니지만 프로젝트를 운영하기 위해서는 반드시 해야 하는 일들이다. Expo는 이런 작업들을 자동화하고 표준화함으로써 개발자가 사용자 가치와 비즈니스 로직에 집중할 수 있게 해준다. CLI에서 Expo로의 전환은 기술 스택 변경을 넘어 개발 방식을 수동 관리의 시대를 지나 시스템 자동화의 시대로 나아가는 전략적 선택이다. 이는 단기적인 편의를 위한 것이 아니라 장기적인 안정성과 생산성을 위한 투자다. 초기 학습 곡선이 있더라도 그 이후로는 일관된 방식으로 작업할 수 있고 팀원이 바뀌어도 프로젝트의 구조를 쉽게 이해할 수 있다. 결론적으로 인프라 구축과 유지보수에 소모되던 에너지를 이제는 사용자 가치를 만드는 비즈니스 로직에 온전히 쏟을 수 있게 되었다. 장기적인 운영 안정성을 고민하는 팀이라면 이 패러다임의 전환은 선택이 아닌 필수적인 투자라고 확신한다. 지금까지의 경험을 돌이켜보면 이 선택이 맞았다고 생각한다.

© 2025 w0nder