Expo EAS Build 오류 해결: 로컬은 되는데 원격 빌드만 실패할 때

2026.05.10·수정 2026.09.13·약 19분·작성: 해비·블로그 소개

학습 목표·선수 지식: EAS 로그를 단계별로 분류하고 원격에 빠진 파일을 아카이브에서 확인합니다. Expo 로컬 실행, Git, eas.json 프로필을 이해해야 합니다.

로컬은 되는데 EAS Build만 실패할 때의 진단 순서

Expo Go에서 실행되는 것과 EAS에서 설치용 앱을 빌드하는 것은 확인 범위가 다릅니다. 원격 빌드만 실패하면 로그의 첫 구체적인 오류와 실패 단계를 먼저 확인합니다. JavaScript 묶음 생성 오류는 npx expo export로 좁히고, 로컬 release 빌드는 성공한다면 업로드 파일·환경변수·도구 버전을 원격과 비교합니다. 아래 단계별 표에서 해당 오류로 바로 이동할 수 있습니다.

최신성 기준: 2026-09-13. 현재 Expo·EAS 공식 문서와 EAS CLI 명령 기준이며, SDK·Node·Xcode·Java 버전은 각 프로젝트의 lockfile과 선택한 EAS build image를 기준으로 고정해야 합니다.

실패 유형과 첫 유효 오류 분류하기

먼저 “빌드가 실패했다”와 “빌드는 성공했지만 설치 후 앱이 종료된다”를 나눕니다. 전자는 EAS Build 단계의 오류이고 후자는 runtime 오류입니다. Expo Go가 정상이라는 사실은 JavaScript 개발 런타임이 동작한다는 뜻일 뿐, 네이티브 모듈을 포함한 release 바이너리·서명·production 환경변수까지 검증했다는 뜻은 아닙니다.

EAS 대시보드에서 실패한 build의 플랫폼, profile, Git commit, Expo SDK, build image, 실패 단계와 로그를 저장합니다. 로그 맨 아래의 포괄적인 Build failed보다 위쪽에 처음 나타난 구체적인 파일명·패키지명·Gradle task·Xcode target 오류를 기준으로 분류합니다. Expo 공식 문제 해결 문서도 로그 확인 후 로컬 release 재현, 환경변수·도구 버전·업로드 파일 비교 순서를 권장합니다.

처음 실패한 단계대표 단서먼저 확인할 입력
프로젝트 아카이브·업로드파일 없음, 모듈 경로 없음.gitignore, .easignore, 경로 대소문자
dependency installimmutable lockfile, package not foundlockfile, package manager, private registry token
app config·Prebuildplugin, package name, bundle identifier 오류profile 환경, 최종 app config, config plugin
native compileGradle, Kotlin, CocoaPods, Xcode 오류SDK 호환성, native module, build image
credentials·signingkeystore, certificate, provisioning 오류앱 식별자, 인증서·프로파일·권한
빌드 성공 후 runtime즉시 종료, splash 화면 멈춤production bundle, 환경변수, 네이티브 런타임 로그

재시도마다 build URL과 변경 한 가지를 함께 기록합니다. profile, 패키지, 캐시를 한 번에 모두 바꾸면 어떤 수정이 원인이었는지 확인할 수 없습니다. 로그를 공유할 때는 토큰, 서명 파일 내용, 인증서 비밀번호와 환경변수 값을 제거합니다.

이전에 성공한 빌드가 있다면 Compare로 차이 확인

EAS 대시보드에서 실패한 빌드의 상세 화면을 열고 Compare에 이전 성공 빌드의 ID 또는 전체 URL을 입력합니다. 환경·Expo SDK 같은 빌드 정보와 단계별 로그를 나란히 비교할 수 있습니다. 먼저 실패한 단계에서 파일·패키지·설정 중 무엇이 달라졌는지 확인한 뒤 아래 재현 단계로 진행합니다. 비교 결과에 차이가 있다는 사실만으로 원인이 확정되는 것은 아니므로 한 항목씩 검증합니다.

이 비교 기능과 로컬 release 재현 절차는 Expo 공식 빌드 문제 해결 문서에서 확인할 수 있습니다. 성공한 빌드 이력이 없다면 바로 production bundle과 release 조건 확인부터 시작합니다.

release 조건으로 로컬 재현하기

개발 서버 대신 가장 싼 단계부터 release 조건을 올립니다. JavaScript bundle이나 production 환경 분기 문제는 npx expo export로 빠르게 드러날 수 있습니다. 그다음 네이티브 도구가 설치된 환경에서 Android release와 iOS Release 설정을 각각 실행합니다.

# JavaScript production bundle 확인
npx expo export

# Android release native compile
npx expo run:android --variant release

# iOS Release native compile: macOS와 Xcode 필요
npx expo run:ios --configuration Release

여기서도 실패하면 원격 서비스보다 프로젝트의 bundle·native 설정 문제일 가능성이 큽니다. 로컬 release가 성공한 뒤 EAS만 실패한다면 원격과 다른 세 가지 입력, 즉 도구 버전, 환경변수, 업로드 아카이브를 우선 비교합니다. 공식 문서가 제시하는 이 세 조건은 “로컬은 된다”를 검증 가능한 문장으로 바꾸는 기준입니다.

호스트에 필요한 native toolchain이 있다면 EAS 서버 단계와 더 가까운 로컬 빌드도 실행할 수 있습니다. 같은 플랫폼과 profile을 반드시 적습니다.

eas build --platform android --profile preview --local

# macOS에서 iOS를 재현할 때
eas build --platform ios --profile production --local

EAS 로컬 빌드 공식 문서에 따르면 --local은 원격 단계와 최대한 가까운 흐름을 실행하지만 호스트 운영체제와 설치된 toolchain까지 동일하게 만들어 주지는 않습니다. Windows의 Android 로컬 EAS Build는 first-class 지원이 아니며 WSL로 가능할 수 있고, iOS 로컬 compile은 macOS가 필요합니다. 로컬에서 재현하지 못했다고 곧바로 EAS 서비스 장애로 결론 내리면 안 됩니다.

EAS Build 진단: 로컬 성공, 원격 실패, 환경 차이

업로드 아카이브와 대소문자 경로 확인하기

로컬 파일이 존재해도 EAS 서버에 업로드되지 않으면 원격에서는 없는 파일입니다. 기본적으로 EAS CLI는 .gitignore를 따르고, 프로젝트 루트에 .easignore가 있으면 그것을 우선합니다. .easignore 공식 문서대로 새 파일을 만들 때는 기존 .gitignore 규칙도 포함해야 하며, 필요한 비추적 파일은 마지막에 ! 예외 규칙으로 포함할 수 있습니다.

# 어떤 ignore 규칙이 파일을 제외하는지 확인
git check-ignore -v path/to/required-file.json

# EAS에 전달될 archive 단계를 별도 폴더로 검사
npx eas-cli@latest build:inspect -p android --profile preview -s archive -o .eas-build-archive

현재 EAS CLI 공식 레퍼런스build:inspectarchive, pre-build, post-build 단계를 출력할 수 있습니다. 생성된 archive에서 로컬 config plugin, 인증에 필요한 설정 파일의 자리, workspace package와 native 디렉터리가 실제로 존재하는지 봅니다. 단, 비밀 파일을 저장소에 커밋하는 해결책은 피하고 EAS file environment variable이나 빌드 단계의 안전한 주입 방식을 사용합니다.

  • src/Api.ts를 import하면서 실제 파일이 src/api.ts라면 깨끗한 clone이나 원격 파일 시스템에서만 오류가 드러날 수 있습니다. import와 실제 이름의 대소문자를 정확히 맞춥니다.
  • androidios 디렉터리가 archive에 없으면 EAS Build는 Prebuild로 생성할 수 있습니다. 직접 관리하는 native 변경이 있다면 이 디렉터리가 의도치 않게 ignore되지 않았는지 확인합니다.
  • monorepo는 앱 루트뿐 아니라 workspace package, lockfile, 설정 파일이 archive에 포함되는지 확인합니다.

대소문자 차이를 Git 기록까지 수정하기

예를 들어 import는 src/api.ts인데 저장소에는 src/Api.ts가 있을 때, 대소문자를 구분하지 않는 로컬 파일 시스템에서는 변경이 누락될 수 있습니다. 다음은 실제 파일명이 Api.ts인 프로젝트에서 소문자 이름으로 통일하는 수정 예시입니다. 경로가 다르면 그대로 실행하지 말고 실제 파일에 맞추세요.

git mv src/Api.ts src/api-rename-temp.ts
git mv src/api-rename-temp.ts src/api.ts
git diff --cached --name-status

모든 import가 새 이름과 같은지 검색하고 새 아카이브에서 소문자 경로가 포함됐는지 확인합니다. 아카이브 검사 디렉터리는 앱 소스 밖에 두거나 .easignore에서 제외해 다음 업로드에 섞이지 않게 하세요. 수정 후 비교할 것은 같은 commit·preview 프로필의 import 오류 소멸이며, 네이티브 컴파일·서명 성공은 각각 별도 단계입니다.

profile·환경변수·최종 app config 맞추기

eas build --profile previeweas.jsonbuild.preview를 사용합니다. --profile을 생략하면 production profile이 있으면 그것이 기본이므로, 실행 명령과 기대 환경이 다를 수 있습니다. 환경 선택을 암묵적인 distribution 규칙에 맡기지 않고 profile에 명시하면 Build와 Update의 값을 맞추기 쉽습니다.

설정 예시: eas.json의 해당 객체에 병합합니다. 기존 설정은 보존합니다.

{
  "build": {
    "preview": {
      "distribution": "internal",
      "environment": "preview"
    },
    "production": {
      "environment": "production"
    }
  }
}

로컬 .env.local은 보통 Git에서 제외되므로 원격 job에 자동으로 존재하지 않습니다. EAS 환경변수 공식 문서에 따라 EAS에 environment별 값을 만들고, 선택한 profile의 environment와 맞춥니다. 앱 클라이언트 코드에 들어가는 EXPO_PUBLIC_ 값은 번들 사용자가 읽을 수 있으므로 비밀키를 넣으면 안 됩니다.

# 값 자체를 로그에 붙이지 말고 이름·환경·visibility를 확인
eas env:list --environment preview

# 현재 로컬 환경에서 해석된 최종 공개 config 확인
npx expo config --type public

동적 app.config.ts가 앱 이름, android.package, ios.bundleIdentifier, config plugin 옵션을 환경변수로 만든다면 최종 config를 profile별로 비교합니다. Plain text와 Sensitive 변수는 EAS CLI의 build config 해석에도 사용할 수 있지만 Secret은 EAS 서버 밖에서 읽을 수 없습니다. 로컬 config 해석에도 반드시 필요한 값을 Secret로만 두면 undefined가 될 수 있으므로 목적과 visibility를 맞춥니다. Secret 값을 앱 번들에 넣는 것은 visibility와 상관없이 안전하지 않습니다.

lockfile·SDK·빌드 도구 버전 맞추기

EAS Build는 기본적으로 선택된 패키지 매니저의 immutable 방식, 예를 들어 npm의 npm ci나 Yarn의 --frozen-lockfile로 의존성을 설치합니다. 로컬에서 package.json만 바꾸고 lockfile을 갱신하지 않았거나 여러 종류의 lockfile이 섞여 있으면 원격 install 단계에서 먼저 실패할 수 있습니다. EAS dependency cache 공식 문서도 immutable lockfile 설치를 기본으로 설명합니다.

# 현재 Expo 프로젝트 상태와 config·dependency 호환성 점검
npx expo-doctor

# 변경 없이 호환 버전 차이만 확인
npx expo install --check

# 결과를 검토한 뒤 호환 버전으로 수정할 때만 실행
npx expo install --fix

원문의 npx expo doctor가 아니라 현재 공식 명령은 Expo 개발 도구 문서npx expo-doctor입니다. --fix는 실제 dependency와 lockfile을 바꿀 수 있으므로 먼저 --check 결과를 읽고 변경 diff와 native module 호환성을 확인합니다.

eas.json 공식 문서에서는 build profile에 Node와 패키지 매니저 버전, 플랫폼별 image를 지정할 수 있습니다. 로컬 성공 환경의 버전을 기록한 다음 필요한 값만 고정합니다. 무조건 latest로 올리거나 오래된 버전을 복사하는 대신 Expo SDK가 지원하는 build image와 lockfile 조합을 사용해야 합니다.

EAS Build 진단 해결: profile, 환경변수, native compile

플랫폼별 native compile과 credentials 분리하기

범위로그에서 볼 항목확인할 설정
Android실패한 Gradle task, Kotlin·Java compile, manifest mergeandroid.package, keystore, config plugin, Gradle·JDK·SDK
iOSpod install, Xcode target, entitlement, code signingios.bundleIdentifier, certificate, provisioning profile, capability
공통dependency install, Metro bundle, PrebuildExpo SDK, lockfile, environment, 업로드 archive

한 플랫폼만 실패하면 공통 JavaScript 코드를 무작정 고치기보다 그 플랫폼의 첫 native 오류를 봅니다. Android 앱 식별자가 keystore나 Google 서비스 파일과 다르거나, iOS capability가 바뀌었는데 provisioning profile이 갱신되지 않은 경우가 대표적입니다. EAS가 credentials를 관리하는 프로젝트도 앱 식별자와 계정 권한이 맞아야 합니다.

CNG 프로젝트에서 native 디렉터리를 커밋하지 않으면 Prebuild가 app config와 config plugin으로 새 프로젝트를 생성합니다. 반대로 androidios를 직접 관리해 업로드하면 그 native 프로젝트가 빌드 입력입니다. 로컬에서 수동으로 바꾼 native 파일이 config plugin에 반영되지 않은 채 archive에서 제외되는 상황을 구분해야 합니다.

캐시와 로컬 빌드의 예외 확인하기

  • 캐시는 마지막 가설: lockfile, environment, archive가 같은데 오래된 artifact가 의심될 때만 eas build --platform android --profile preview --clear-cache로 한 번 비교합니다. --clear-cache는 현재 EAS CLI의 유효한 옵션이지만 누락 파일이나 잘못된 credentials를 고치지 않습니다.
  • 빌드 성공 후 crash는 별도 문제: npx expo export, production 환경변수, 기기 로그를 확인합니다. 빌드 단계의 cache clear만 반복하지 않습니다.
  • private package: 로컬 로그인 상태가 원격에 없을 수 있습니다. registry URL, lockfile, 원격 job에서 사용할 최소 권한 토큰의 이름을 확인하되 토큰 값을 로그로 출력하지 않습니다.
  • 서비스 장애: 같은 commit·profile이 과거에 성공했고 입력 차이가 없으며 여러 프로젝트에서 동일 단계가 실패할 때만 EAS 상태를 별도 가설로 둡니다.
  • 로컬 clean 재현: 기존 node_modules와 전역 설정에 기대지 않는 새 clone에서 immutable install과 release build를 통과해야 원격과 비교할 근거가 생깁니다.

수정 결과 검증과 결론

원인 하나를 수정한 뒤 실패했던 것과 같은 platform, profile, environment로 다시 빌드합니다. 단순히 status가 finished가 됐는지만 보지 말고 설치 가능한 artifact를 내려받아 시작, 핵심 화면, API 환경, 서명된 앱 식별자를 확인합니다.

검증 항목통과 기준남길 증거
업로드 입력필요 파일과 workspace가 archive에 존재build:inspect 단계와 파일 목록
환경·config선택한 environment의 package·bundle identifier·공개 config 일치값을 가린 config diff와 profile 이름
dependencyimmutable install과 Expo 호환성 검사 통과lockfile hash, 패키지 매니저, expo-doctor 결과
native release동일 플랫폼 release compile 통과로컬 명령과 toolchain 버전
EAS 원격 build같은 profile에서 artifact 생성build URL·ID, commit, image, 실패 전후 단계
설치 후 실행실기기·에뮬레이터에서 시작과 핵심 흐름 정상앱 버전, 플랫폼, 테스트 결과

결론은 간단합니다. EAS Build만 실패하면 로컬 개발 서버가 아니라 원격에 전달된 입력을 비교해야 합니다. 첫 유효 오류를 단계별로 분류하고, release build로 재현한 뒤, archive·environment·lockfile·toolchain·credentials 중 다른 한 가지를 수정합니다. 같은 platform과 profile의 원격 빌드와 설치 테스트까지 통과하면 해결된 것입니다.

다음 학습 경로

과정 마무리 실습

목록과 상세 화면, 텍스트 입력, 안전 영역을 갖춘 작은 앱을 만드세요.

완료 기준: 좁은 화면·키보드 표시·뒤로 이동을 확인합니다. 기기 설치와 원격 빌드는 별도 실행 항목으로 기록합니다.

이어서 공부할 과정: 테스트 첫 글

전체 학습 경로

문서·검증 기준 (2026-09-13): 해당 기능의 Expo 공식 문서와 코드 구조를 대조했습니다. 설치 버전은 프로젝트 Expo SDK에 맞는 npx expo install 결과와 lockfile을 기준으로 합니다. 이번 개정에서는 실제 Android·iOS 기기 실행, 원격 EAS 빌드, 외부 인증 서버 연동을 수행하지 않았습니다. 본문의 기기 동작은 독자가 확인할 기대 결과입니다.

이 글이 도움이 되었나요?

조회 중

Expo 학습 순서

필수 9개 · 전체 13개

읽음 기록 관리

전체 과정 목차 (13개)
  1. 필수 학습 · Expo 첫 앱 만들기: 설치·프로젝트 생성부터 첫 화면 실행까지
  2. 필수 학습 · Expo Safe Area 사용법: 화면 여백을 안전하게 잡는 방법
  3. 필수 학습 · Expo Status Bar 사용법: Safe Area와 화면별 설정
  4. 필수 학습 · Expo vector icons 사용법: 탭바와 커스텀 아이콘 적용하기
  5. 필수 학습 · Expo KeyboardAvoidingView 사용법: 키보드가 화면을 가릴 때 해결하기
  6. 필수 학습 · Expo Router 사용법: app 폴더와 Stack Tabs 구조 잡기
  7. 필수 학습 · Expo WebBrowser 사용법: 외부 링크와 로그인 복귀 처리
  8. 필수 학습 · Expo SecureStore 사용법: 토큰 저장과 생체 인증 처리
  9. 선택 참고 · Expo Location 사용법: 현재 위치와 백그라운드 추적 처리
  10. 선택 참고 · Expo React Native Web 사용법: 앱을 웹으로 확장하기
  11. 선택 참고 · Expo Metro unable to resolve module 오류 해결: 경로와 캐시
  12. 필수 학습 · Expo EAS Build 시작하기: Android APK 빌드부터 설치 확인까지
  13. 선택 참고 · Expo EAS Build 오류 해결: 로컬은 되는데 원격 빌드만 실패할 때 현재 글

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기