Expo EAS Build & EAS Update 완벽 가이드 2026: 클라우드 빌드부터 OTA 배포까지
Expo EAS Build와 EAS Update로 macOS 없이 React Native 앱을 클라우드 빌드하고, 앱 스토어 검수 없이 OTA로 즉시 배포하는 2026년 실전 가이드. eas.json 프로필부터 fingerprint 런타임, 채널/브랜치 운영, 자동 제출 파이프라인까지 모든 단계를 다룹니다.
Expo EAS Build와 EAS Update는 React Native 앱을 클라우드에서 빌드하고 OTA(Over-the-Air) 방식으로 즉시 배포할 수 있게 해주는 Expo의 통합 배포 플랫폼입니다. EAS Build는 Android APK·AAB와 iOS IPA를 macOS 없이도 생성하며, EAS Update는 JavaScript 번들과 자산을 앱 스토어 검수 없이 사용자에게 푸시합니다. 2026년 현재 두 서비스는 fingerprint 기반 런타임 버전 관리와 Continuous Native Generation(CNG)을 통해 통합된 워크플로우를 제공합니다.
솔직히 말하면, 저는 작년에 결제 흐름 버그를 새벽 2시에 발견하고 EAS Update로 8분 만에 푸시했던 경험이 있는데, 그때 처음으로 OTA의 진가를 체감했습니다. 앱 스토어 검수 사흘을 기다렸다면 매출 손실이 컸을 겁니다. 이 글은 그런 실전 시나리오를 염두에 두고 정리한 가이드입니다.
EAS Build는 macOS 없이 iOS·Android 네이티브 빌드를 클라우드에서 생성하며, eas.json의 빌드 프로필(development·preview·production)로 환경을 분리합니다.
EAS Update는 JavaScript·자산만 변경된 경우 앱 스토어 재제출 없이 1분 이내에 사용자에게 패치를 배포합니다.
런타임 버전(runtimeVersion)은 어떤 OTA 업데이트가 어떤 네이티브 빌드와 호환되는지 결정하며, 2026년부터 `fingerprint` 정책이 기본 권장입니다.
업데이트 채널(channel)과 브랜치(branch)를 분리하면 production·preview·staging 트래픽을 독립적으로 라우팅할 수 있습니다.
EAS Submit은 IPA·AAB 산출물을 App Store Connect·Google Play Console에 자동 업로드해 출시 파이프라인을 한 줄 명령으로 완결합니다.
2026년 무료 플랜은 월 30회 빌드와 무제한 OTA 업데이트(MAU 1,000명 한도)를 제공합니다.
EAS Build와 EAS Update란 무엇인가요?
EAS(Expo Application Services)는 Expo가 운영하는 클라우드 기반 React Native 배포 플랫폼으로, Build·Update·Submit·Metadata·Workflows 다섯 가지 핵심 서비스로 구성됩니다. 이 가운데 가장 많이 쓰이는 두 축이 EAS Build와 EAS Update입니다. EAS Build는 Expo 워크플로우(Managed)뿐 아니라 베어 React Native 프로젝트도 지원하며, Xcode·Android Studio 없이 GitHub Actions나 로컬 머신에서 트리거된 작업을 Expo의 macOS·Linux 빌더에서 실행해 서명까지 마친 산출물을 반환합니다.
EAS Update는 코드 푸시(CodePush)의 후속 격으로, JavaScript 번들과 자산(이미지·폰트)만 변경된 빌드를 사용자의 기기로 직접 배포합니다. 네이티브 모듈이 변경되지 않은 변경사항, 즉 UI 수정·카피 변경·로직 패치·버그 픽스는 모두 OTA로 처리할 수 있어 앱 스토어 검수의 1~7일 지연을 우회할 수 있습니다. 2024년 Microsoft가 CodePush를 단종한 이후, EAS Update는 React Native 진영의 사실상 표준 OTA 솔루션이 되었습니다.
EAS Build 설정과 첫 클라우드 빌드 실행하기
EAS Build를 시작하려면 먼저 공식 EAS Build 설정 문서가 권장하는 순서대로 CLI를 설치하고 프로젝트를 초기화해야 합니다. 다음 명령은 빈 프로젝트에서 첫 빌드를 만들기까지의 표준 흐름입니다.
# 1. eas-cli 전역 설치 (Node 20 LTS 이상 권장)
npm install -g eas-cli@latest
# 2. Expo 계정 로그인
eas login
# 3. 프로젝트 루트에서 EAS 설정 초기화
cd my-rn-app
eas init
# 4. eas.json 자동 생성 및 첫 빌드 트리거
eas build:configure
eas build --platform android --profile development
eas init은 프로젝트에 고유한 projectId(UUID)를 발급하고 app.json의 extra.eas.projectId에 기록합니다. 이 ID는 빌드와 업데이트가 같은 프로젝트를 가리키도록 묶어 주는 키이므로 git에 반드시 커밋해야 합니다. 처음 eas build를 실행하면 iOS는 push notification·distribution 인증서, Android는 keystore를 EAS가 자동 생성·관리할지 묻습니다. 대부분의 팀은 EAS가 자격 증명을 보관하도록 두는 것이 권장되며, 직접 관리하려면 credentials.json으로 수동 구성할 수 있습니다.
빌드는 평균적으로 Android 8~12분, iOS 15~25분이 걸리며 EAS 대시보드 또는 eas build:list로 진행 상황을 확인할 수 있습니다. 완료된 산출물은 24시간 동안 다운로드 가능한 안전한 URL로 제공되고, 시뮬레이터용 빌드(--profile preview)는 Mac iOS 시뮬레이터에 직접 드래그해 설치할 수 있습니다. 처음 빌드를 만들 때는 internal distribution 프로필을 먼저 시도해 TestFlight·Play Console 검수 없이 개발팀이 즉시 검증할 수 있는 빠른 피드백 루프를 만드는 것이 좋습니다.
eas.json 빌드 프로필 완전 분석
eas.json은 EAS의 단일 진실 공급원입니다. 각 build 프로필은 환경 변수, 빌드 채널, 자격 증명 소스, 캐싱 정책을 한 곳에서 정의합니다. 2026년 EAS Build 표준 권장 구성은 다음과 같습니다.
주목할 옵션은 appVersionSource: "remote"입니다. 2026년부터 EAS가 권장하는 이 모드는 versionCode·buildNumber를 EAS 서버가 단조 증가시키도록 위임해, 여러 개발자가 동시에 빌드해도 충돌 없이 고유한 버전 번호를 보장합니다. developmentClient: true는 Expo Go 대신 자체 dev client를 포함시켜 커스텀 네이티브 모듈도 즉시 디버깅할 수 있게 해줍니다. 저는 지난 프로젝트에서 이 옵션을 처음에 빠뜨려서 절반의 시간을 Expo Go에서 모듈 충돌과 씨름하는 데 썼는데, 한 번 켜 두면 정말 두 번 다시 못 끄게 됩니다.
EAS Update로 OTA 배포 구현하기
EAS Update를 사용하려면 expo-updates 모듈을 설치하고 프로젝트를 한 번 빌드해야 합니다. 이미 EAS Build로 빌드한 프로젝트는 추가 설정 없이 OTA를 사용할 수 있습니다.
# expo-updates 설치 및 EAS Update 활성화
npx expo install expo-updates
eas update:configure
# JavaScript 변경사항을 production 채널로 즉시 배포
eas update --branch production --message "v1.2.1: 결제 화면 버그 수정"
# 특정 빌드 프로필과 연결된 채널로 한꺼번에 배포
eas update --auto
eas update:configure는 app.json에 updates.url과 runtimeVersion 정책을 자동 추가합니다. 그 다음 eas update를 실행하면 Metro가 JS 번들을 만들고, 자산을 해시·업로드한 뒤 새 업데이트 그룹을 생성해 해당 채널을 구독한 모든 기기에 게시합니다. 기기는 다음 콜드 스타트 시 Updates.checkForUpdateAsync()를 호출해 새 번들을 다운로드합니다.
앱 내에서 명시적으로 업데이트를 트리거하려면 expo-updates의 hook과 명령형 API를 함께 사용합니다.
import * as Updates from 'expo-updates';
import { useEffect } from 'react';
import { Alert } from 'react-native';
export function useOtaUpdater() {
const { isUpdateAvailable, isUpdatePending } = Updates.useUpdates();
useEffect(() => {
if (isUpdatePending) {
// 새 번들이 디스크에 준비됨, 사용자 동의 후 재시작
Alert.alert('업데이트 준비 완료', '앱을 재시작해 적용할까요?', [
{ text: '나중에', style: 'cancel' },
{ text: '재시작', onPress: () => Updates.reloadAsync() },
]);
}
}, [isUpdatePending]);
useEffect(() => {
if (isUpdateAvailable) Updates.fetchUpdateAsync();
}, [isUpdateAvailable]);
}
이 패턴은 사용자가 화면 전환 도중 강제로 재시작되는 경험을 방지하면서도 다음 콜드 스타트가 아닌 즉시 업데이트를 받아낼 수 있게 해줍니다. 결제·인증처럼 미들 세션 중단이 위험한 경우 isUpdatePending 체크를 화면 라우터 진입 지점에서만 수행하세요.
런타임 버전과 업데이트 채널 관리 전략
EAS Update의 가장 중요한 개념은 런타임 버전(runtimeVersion)입니다. 이는 "어떤 네이티브 바이너리가 어떤 JS 번들을 실행할 수 있는가"를 결정하는 호환성 키로, 잘못 설정하면 사용자가 충돌하는 번들을 받아 앱이 크래시할 수 있습니다. 2026년부터 Expo는 fingerprint 정책을 기본 권장합니다.
정책
동작 방식
장점
단점
appVersion
app.json의 version 필드 사용
설정이 단순
네이티브 변경을 추적하지 못함
sdkVersion
Expo SDK 버전 사용
SDK 호환성 명확
같은 SDK 내 네이티브 변경 불가
nativeRuntimeVersion
수동으로 문자열 지정
완전한 제어
관리 부담, 휴먼 에러 위험
fingerprint (권장)
네이티브 의존성 해시 자동 계산
네이티브 변경 자동 감지, CNG와 완벽 통합
해시 계산에 수 초 추가
채널(channel)은 빌드 시점에 바이너리에 박히는 고정된 라우팅 이름이고, 브랜치(branch)는 채널이 어떤 업데이트 묶음을 가리키는지를 결정하는 가변 포인터입니다. 예를 들어 preview 채널을 평소에는 staging 브랜치에 연결해 두었다가, 핫픽스를 production 사용자에게도 빠르게 시험하고 싶을 때 일시적으로 hotfix-2025-06 브랜치로 전환할 수 있습니다. 이 분리는 빌드를 다시 만들지 않고도 라우팅을 바꿀 수 있게 해 주는 EAS의 핵심 운영 도구입니다. 자세한 배포 운영 패턴은 React Native 성능 최적화 가이드의 메트릭 수집 워크플로우와 함께 구성하면 효과적입니다. 카나리 배포가 필요하다면 5% 사용자에게만 새 브랜치를 노출한 뒤 크래시율이 안정화되면 전체로 확장하는 단계적 롤아웃을 채널 전환으로 구현할 수 있습니다.
EAS Submit으로 앱 스토어 자동 제출
빌드된 IPA·AAB를 수동으로 App Store Connect나 Play Console에 업로드하는 작업은 30분 이상 걸리고 실수도 잦습니다. EAS Submit은 이 과정을 한 줄 명령으로 자동화합니다.
# 마지막 production 빌드를 양 스토어에 자동 제출
eas submit --platform all --latest
# 특정 빌드 ID를 지정해 제출
eas submit --platform ios --id 9c8b...d1e2
# CI에서 빌드 직후 자동 제출 (auto-submit)
eas build --platform all --profile production --auto-submit
iOS의 경우 EAS가 App Store Connect API 키를 안전하게 보관하고 자동 인증합니다. Android는 Google Play Console에서 발급한 서비스 계정 JSON 키를 EAS 시크릿으로 업로드해 두면 됩니다. --auto-submit 플래그는 빌드가 성공하는 즉시 internal 또는 production 트랙으로 업로드하므로, 트렁크 기반 개발과 결합해 매일 internal 테스트 빌드를 자동 배포하는 파이프라인을 30분 만에 구축할 수 있습니다. 메타데이터(스크린샷, 앱 설명, 키워드)는 별도 서비스인 EAS Metadata로 동일하게 코드화해 store-config.json 하나로 양 스토어를 동기화할 수 있습니다.
프로덕션 배포 워크플로우 모범 사례
실전에서 검증된 EAS 프로덕션 파이프라인은 다음 세 단계로 구성됩니다. 각 단계는 GitHub Actions·GitLab CI·Bitbucket Pipelines 어디서든 동일하게 동작합니다.
PR 머지 → preview 빌드 자동 생성: main 브랜치에 머지되면 eas build --profile preview --non-interactive를 실행해 QA 팀이 즉시 설치할 수 있는 internal 빌드를 만듭니다. 빌드 URL은 Slack으로 자동 게시합니다.
릴리스 태그 → production 빌드 + auto-submit:v1.4.0 형식의 시맨틱 버전 태그가 푸시되면 eas build --profile production --auto-submit으로 양 스토어에 동시 업로드합니다.
핫픽스 → EAS Update만 게시: 네이티브 변경이 없는 긴급 수정은 eas update --branch production --message "$(git log -1 --pretty=%s)"로 5분 안에 사용자에게 도달합니다.
이 파이프라인은 React Native 테스트 자동화 워크플로우와 결합되어야 합니다. 매 PR마다 Jest 단위 테스트와 Maestro E2E를 통과한 빌드만 EAS로 넘어가도록 게이트를 설치하면, 잘못된 OTA가 production에 푸시되는 사고를 예방할 수 있습니다. EAS Workflows 공식 가이드는 YAML 한 파일로 빌드·테스트·업데이트·제출 단계를 선언적으로 묶는 새 기능을 소개하며, 2026년 1월 GA 이후 빠르게 표준 도구로 자리잡고 있습니다.
OTA 배포 후 즉시 모니터링해야 할 지표는 업데이트 채택률(adoption rate)과 크래시율 변동입니다. EAS 대시보드의 Insights 탭은 각 업데이트 그룹의 활성 사용자 수와 다운로드 성공률을 제공하며, Sentry나 Bugsnag와 통합하면 특정 업데이트 그룹에서만 발생하는 회귀를 빠르게 격리할 수 있습니다. 채택률이 60% 미만에서 정체된다면 사용자가 앱을 백그라운드에 두고 콜드 스타트하지 않는 경우가 많다는 신호이므로, 위에서 본 useOtaUpdater 훅을 활성화해 적극적으로 fetchUpdate를 호출하세요.
자주 발생하는 문제와 해결 방법
EAS를 운영하다 보면 빌드 실패와 OTA 미적용 문제가 가장 자주 발생합니다. 다음은 현장에서 가장 흔한 다섯 가지 사례와 해결책입니다. 솔직히 저도 1번과 4번은 각각 두 번씩 당했습니다.
"Fingerprint mismatch" 오류로 OTA가 무시됨: 네이티브 의존성을 추가했는데 새 빌드를 만들지 않았을 때 발생합니다. npx expo install로 native 모듈을 추가한 직후에는 반드시 새 production 빌드를 만들어야 합니다.
iOS 빌드가 "No matching profiles found"로 실패: EAS가 관리하는 자격 증명이 만료된 경우입니다. eas credentials를 실행해 distribution 인증서를 갱신하세요.
Android keystore를 잃어버린 경우: EAS가 자격 증명을 관리하고 있었다면 eas credentials에서 다운로드할 수 있습니다. 직접 관리했고 백업이 없다면 Play Console의 Play App Signing이 활성화돼 있는지 확인하세요. 활성화되어 있다면 새 upload key 발급으로 복구 가능합니다.
업데이트 채택률이 0%: 빌드의 채널과 업데이트의 채널이 일치하는지, runtimeVersion 정책이 같은지 가장 먼저 확인하세요. eas update:view 명령으로 특정 그룹의 대상 채널을 정확히 조회할 수 있습니다.
EAS Build가 "Out of memory": Metro의 번들링이 메모리를 다 쓰는 경우입니다. eas.json의 resourceClass를 large 또는 m-large로 올리면 16GB까지 할당됩니다(유료 플랜).
네, 무료 Free 플랜은 월 30회의 클라우드 빌드와 무제한 OTA 업데이트를 제공합니다. 단 OTA의 경우 월 1,000명 MAU 한도가 있으며, 우선 빌드 큐가 아닌 일반 큐를 사용해 평균 대기 시간이 5~15분 더 깁니다. 프로덕션 트래픽이 있다면 월 $19부터 시작하는 Production 플랜을 권장합니다.
OTA 업데이트로 네이티브 코드까지 변경할 수 있나요?
아니요. EAS Update는 JavaScript 번들과 자산(이미지·폰트·JSON)만 변경할 수 있습니다. 네이티브 의존성, Info.plist, AndroidManifest.xml, 권한, 네이티브 모듈 버전이 변경된 경우 반드시 새 빌드를 만들고 앱 스토어에 재제출해야 합니다. fingerprint 정책이 이런 변경을 자동으로 감지해 호환되지 않는 업데이트가 푸시되는 것을 막아줍니다.
EAS Update와 Microsoft CodePush 중 무엇을 선택해야 하나요?
EAS Update를 선택하세요. Microsoft는 2025년 3월 CodePush의 단종을 발표했고 신규 가입을 받지 않습니다. EAS Update는 expo-updates 모듈로 베어 React Native 프로젝트에서도 동작하며, fingerprint 런타임 버전·채널/브랜치 분리·EAS Insights 통합 등 CodePush에 없던 운영 기능을 제공합니다.
빌드 시간이 너무 오래 걸리면 어떻게 단축할 수 있나요?
가장 효과적인 방법은 npm·CocoaPods·Gradle 캐시 적중률을 높이는 것입니다. eas.json의 cache.key를 잠금 파일 해시로 설정하고, 큰 자산은 Hermes 정밀 번들링에서 제외하세요. iOS는 resourceClass: "m-medium"(Apple Silicon)으로 전환하면 평균 30~40% 빨라집니다. CI에서 동시 빌드가 많다면 Production 플랜의 우선 큐가 가장 큰 단축 효과를 가져옵니다.
EAS 없이 expo-updates만 사용해 자체 OTA 서버를 운영할 수 있나요?
가능합니다. expo-updates는 표준 업데이트 프로토콜을 준수하며, app.json의 updates.url을 자체 서버로 지정하면 자체 호스팅이 됩니다. 다만 CDN·서명 검증·롤백·인사이트를 직접 구현해야 하므로 운영 비용이 큽니다. 팀이 5명 미만이라면 EAS Update를 사용하는 것이 거의 항상 더 경제적입니다.