Expo ile uygulama geliştirme: girişimciler için 2026 rehberi

Kurucu olarak uygulamanızı nasıl geliştireceğinize karar vermeye çalışıyorsunuz ve araştırırken bir yazılımcıdan 2020'de herkesin söylediği şeyi duydunuz: Expo prototip için iyidir ama ciddi bir şey yayınlamadan önce "eject" etmeniz gerekir. Bu tavsiyenin modası geçti. Ona uyarsanız ihtiyacınız olmayan native kurulum işlerine haftalarınızı verirsiniz.
Bunu uzaktan yorum yapan biri olarak söylemiyoruz. App Store ve Play Store'da yayında olan kendi abonelikli uygulamalarımızı tam olarak bu altyapıda çalıştırıyoruz, müşteri uygulamalarını da aynı altyapıyla geliştiriyoruz. Aşağıda anlattığımız her şey, başımızı yakan kısımlarıyla birlikte, her hafta fiilen yaptığımız işler.
Gerçekte ne kullanıyoruz: sürüm numaralarıyla
Çoğu Expo yazısı, yazarın kendisinin ne yayınladığını hiç söylemez. Aşağıda Eylül 2026 itibarıyla aktif uygulamalarımız var; sürümler doğrudan her uygulamanın package.json dosyasından alındı. Listede ayrıca, sonlandırmadan önce aynı altyapıda yayınladığımız Flast de var. Yayındaki uygulamalara ürünler sayfamızdan ulaşabilir, birini indirip kendiniz görebilirsiniz.
Nail Mirror expo ^57.0.0 react-native 0.86.3
Curtain AI expo ~56.0.16 react-native 0.85.3
FiberCheck expo ~56.0.16 react-native 0.85.3
Pass the Phone expo ~56.0.16 react-native 0.85.3
Bluffin expo ~55.0.28 react-native 0.83.6
Be Judge expo ~55.0.28 react-native 0.83.6
OK or NOK? expo ~54.0.36 react-native 0.81.5
Flast expo ~54.0.29 react-native 0.81.5 discontinued
Bu listeden iki sonuç çıkıyor. Birincisi, Nail Mirror en yeni SDK'de: Expo 57, React Native 0.86.3 ile eşleşiyor. Diğer uygulamalarımız ondan sıfır ila üç SDK sürümü geride. Bu bilinçli bir tercih. Ödeme yapan aboneleri olan bir uygulama her yeni sürümün peşinden koşmaz. Yükseltmeyi ancak bir gerekçe olduğunda ve olası bir gerilemenin (regression) bir abonelik yenileme dönemine mal olmayacağı bir zamanda yaparız.
İkincisi, asıl mesele bu dağılımın kendisi. Dört farklı ana SDK sürümüne yayılmış bir portföyü ancak yükseltmeler native birleştirme (merge) değil, bir config değişikliği olduğu için yönetebiliyoruz. Her uygulama ve her platform için ayrı bir native proje klasörünü elle yönetiyor olsaydık bu dağılım tam zamanlı bir iş olurdu. Bugün başlıyorsanız en yeni SDK ile başlayın. Yukarıdaki basamaklı dağılım bir portföy taktiği, yeni bir proje için öneri değil.
"Expo sadece prototip içindir" efsanesi bitti
Eski eleştirinin gerçek bir dayanağı vardı. Yıllar önce Expo'nun pakete eklemediği bir native kütüphane istediğinizde çıkmaza girerdiniz. İki seçeneğiniz vardı: sabit bir native modül setiyle gelen ve korumalı alanda (sandbox) çalışan Expo Go uygulamasının içinde yayınlamak ya da "eject" edip bare bir React Native projesine geçmek ve iOS ile Android klasörlerini kendiniz yönetmek. Expo'nun bu ünü de o yol ayrımından geliyor.
Bu yol ayrımı artık yok. Onu ortadan kaldıran şey development build oldu. Expo'nun kendi dokümantasyonu bunu açıkça söylüyor: development build, özünde sizin kendi Expo Go sürümünüzdür. İstediğiniz native kütüphaneyi kullanabilir, istediğiniz native yapılandırmayı değiştirebilirsiniz. Ortak bir oyun alanı değil, kontrolünüzde olan gerçek bir native binary'dir. Zaten kendi projenizin içindesiniz, dolayısıyla "eject" edilecek bir şey de yok.
Development build'ler "managed mı, bare mi" tartışmasını bitirdi
Seçimi hâlâ "managed workflow mu, bare workflow mu?" diye soran eski blog yazılarına rastlarsınız. Bu soruyu bir kenara bırakın. Güncel model Continuous Native Generation, yani CNG. Bu modelde native projeler bir kez oluşturulup kod tabanı yaşadığı sürece elle özelleştirilmez; kısa ömürlü native projeler yalnızca gerektiğinde, örneğin hata ayıklarken ya da build alırken üretilir. Özelleştirmelerinizin tanımını sürüm kontrolünde tutarsınız. Prebuild ios ve android klasörlerini gerektiğinde yeniden ürettiği için bu klasörlerin yeri .gitignore dosyasıdır ve Expo yeni projelerde onları varsayılan olarak oraya ekler.
React Native'i iki native platformda elle yükseltmek, mobil geliştirmenin en sancılı angaryalarından biridir, çünkü özel düzenlemeleriniz her adımda yükseltmeyle çatışır. CNG'de native proje atılıp yeniden üretilebildiği için yükseltme, birleştirme çakışması maratonu yerine bir config değişikliğine dönüşür. Yukarıdaki dağılımın yönetilebilir olmasının tek nedeni bu özellik.
EAS Build: kendiniz kurmadan hazır yayın hattı
İmzalı bir iOS binary'sini bir cihaza ulaştırmak, ilk kez uygulama çıkaran kurucuları korkutan kısımdır ve korkmakta haksız da sayılmazlar. Sertifikalar, provisioning profile'lar, keystore'lar, Xcode sürümleri ve işin içinde bir Mac. EAS Build, iOS ve Android binary'lerinizi bulutta üreten barındırılan (hosted) bir hizmettir ve bu yükün çoğunu sizin yerinize üstlenir. iOS build'i üretmek için ne bir Mac'e ne de ilk günden elle kurmanız gereken bir CI sunucusuna ihtiyacınız var.
Yapılandırma sanıldığından küçük. Yayındaki uygulamalarımızdan birinin eas.json dosyasının tamamı, hiç düzenlenmeden:
{
"cli": {
"version": ">= 16.9.0",
"appVersionSource": "remote"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"channel": "development"
},
"preview": {
"distribution": "internal",
"android": { "buildType": "apk" },
"channel": "preview"
},
"production": {
"autoIncrement": true,
"channel": "production"
}
},
"submit": { "production": {} }
}
Üç profil, üç kanal ve sizi ciddi baş ağrısından kurtaran iki ayar. appVersionSource: remote, build numaraları konusunda yetkiyi EAS'a verir. Böylece iki ayrı dizüstü bilgisayardan build alan iki kişi aynı sürüm kodunda çakışamaz. Production profilindeki autoIncrement sayesinde de build numarasını hiçbir zaman elle artırmazsınız ve App Store Connect'ten "bu build'i zaten yüklediniz" reddini hiç almazsınız. Kanal adları sonradan önem kazanır: EAS Update, güncellemeleri bu kanallar üzerinden yayınlar.
Pratikte, ikinci haftanın sonunda gerçek cihazınıza bir TestFlight build'i ulaştırabilmemizin nedeni bu. Bu erken cihaz testi, bir uygulama projesinde riski azaltmak için yapılabilecek en etkili hamledir, çünkü simülatörler performans, izinler ve ödemeler konusunda sizi yanıltır. Yürüttüğümüz her ciddi projede ilk iki hafta içinde gerçek cihazda build almak pazarlık konusu değildir.
EAS Update: incelemeyi beklemeden düzeltme yayınlayın
Yayın hattının ikinci yarısı OTA (over-the-air) güncellemeleri. EAS Update, uygulamanızın native olmayan parçalarını, yani JavaScript'i, stilleri ve görselleri, yeni bir mağaza gönderimi yapmadan kendi kendine güncellemesini sağlar. Ödeme ekranındaki (paywall) bir yazım hatası, kötü bir metin, tek bir ekran boyutunda bozulan bir yerleşim: düzeltmeyi gönderirsiniz ve kullanıcılar alır. Sizinle düzeltme arasına günler süren bir inceleme kuyruğu girmez.
Burada kesin bir sınır var ve dokümantasyon bunu net biçimde çiziyor. OTA güncellemeleri JS kodunu, config'i ve asset'leri kapsar. Native kod ya da native bağımlılık değişikliklerini, uygulama izinlerindeki değişiklikleri ve Expo SDK sürüm yükseltmelerini ise açıkça kapsam dışında bırakır. Yeni binary isteyen her değişiklik için yeni bir EAS Build ve yeni bir mağaza gönderimi gerekir. OTA'yı küçük düzeltmeler için bir neşter olarak görün; yeni özellikleri App Store incelemesinin etrafından dolaştırmanın yolu olarak değil. Bu sınırı bulanıklaştıran kurucular er ya da geç ret alır. Bu yüzden native ve OTA değişikliklerini en baştan ayrı tutarız.
Hâlâ framework kararının kendisini tartıyorsanız, artı ve eksilere dair görüşümüz React Native mi Flutter mı yazısında. Bir karara bağlanmadan önce gerçekçi rakamlar görmek isterseniz mobil uygulama yapmanın ne kadar tuttuğunu anlattığımız yazıya göz atın. Bu altyapıyla her hafta uygulama yayınlayan bir ekiple konuşmayı tercih ederseniz 30 dakikalık görüşme planlayın, fikrinizi birlikte bir plana dönüştürelim.
Güncellemeyi kimin alacağına karar veren runtimeVersion tuzağı
Ekiplere bir haftalarını kaybettiren tuzak bu ve başlangıç rehberlerinin neredeyse hiçbiri bundan söz etmez. Bir güncelleme, uygulamanızın her kurulumuna ulaşmaz. Yalnızca runtime sürümü, güncellemenin yayınlandığı runtime sürümüyle eşleşen kurulumlara ulaşır. Expo, runtime sürümlerini bir build'in native kodu ile bir güncelleme arasındaki uyumu garanti eden özellik olarak tanımlar. İkisi uyuşmazsa expo-updates hatayı fark edip, olmayan kodu çalıştırmak yerine daha önce çalışan güncellemeye geri dönebilir.
İlk akla gelen, runtime sürümünü uygulama sürümüne bağlamaktır. Bu refleks, her yeni sürümde kitlenizi sessizce ikiye böler. Uygulamalarımızdan birindeki ayar ise şöyle:
{
"expo": {
"version": "1.12.4",
"runtimeVersion": "1.12.2",
"newArchEnabled": true
}
}
Uygulama sürümü 1.12.4, runtime sürümü ise 1.12.2'ye sabitlenmiş. Bu, düzeltmeyi unuttuğumuz bir yazım hatası değil. 1.12.2, 1.12.3 ve 1.12.4 arasında hiçbir native değişiklik yayınlamadık, bu yüzden üçü tek bir runtime'ı ve tek bir OTA kitlesini paylaşıyor. Runtime 1.12.2 için yayınlanan bir JavaScript düzeltmesi üçüne de ulaşır. Aynı düzeltme appVersion politikasında yalnızca 1.12.4 kurulumlarına ulaşırdı ve uygulamayı mağazadan güncellememiş herkes hatayla süresiz olarak yaşamaya devam ederdi.
Uyguladığımız kural şu: runtime sürümü yalnızca native katman değiştiğinde değişir. Yeni SDK, yeni native bağımlılık ya da yeni izin: yeni runtime. Yalnızca JavaScript içeren sürüm: aynı runtime. Hangi değerin hangi binary ile yayınlandığını not edin, çünkü bir güncelleme ulaşmadığında ilk arayacağınız ama çoğu zaman bulamayacağınız şey o kayıttır. Bunu otomatikleştirmenin yolu fingerprint politikası: değeri, native runtime'ı etkileyen her şeyden türetir. Yayın temponuz elle tutulan bir tabloyu aştığında daha güvenli varsayılan da budur.
Yine de native koda inmeniz gereken durumlar
Expo sihirli değnek değil. Öyleymiş gibi davranırsanız sürprizlerle karşılaşırsınız. Native kod yazmanız ya da mevcut native kodu sarmalamanız (wrap) gereken durumlar var: bakımı süren bir config plugin'i olmayan niş bir SDK, platform API'lerine sıkı bağlı bir donanım ya da Bluetooth entegrasyonu veya native thread'i doğrudan kontrol etmek istediğiniz, performansın kritik olduğu bir yol.
İyi haber şu: bu, ayrı bir yola sapmak değil, mevcut yapıya bir ekleme. Config plugin, Info.plist ya da AndroidManifest.xml dosyalarını elle düzenlemeniz yerine prebuild sırasında native projenizi değiştiren bir fonksiyondur. Pratikte ekiplerin "native iş" sandığı şeylerin çoğu birkaç satırlık config'den ibarettir. Yayındaki uygulamalarımızdan birinde izin metinleri ve native build ayarları şöyle tanımlanıyor:
"plugins": [
"expo-router",
"expo-localization",
"expo-secure-store",
["expo-camera", {
"cameraPermission": "$(PRODUCT_NAME) needs camera access to capture photos of your room for curtain design.",
"recordAudioAndroid": false
}],
["expo-dev-client", { "launchMode": "most-recent" }],
["expo-build-properties", {
"ios": { "useFrameworks": "static", "buildReactNativeFromSource": true }
}]
]
Kamera izni metninin config içinde, İngilizce olarak, ihtiyacımız olmayan ses kaydını kapatan ayarın yanında durduğuna dikkat edin. App Store incelemecisinin okuduğu cümle bu ve otomatik üretilen bir plist'in içine gömülü değil, sürüm kontrolünde duruyor. Bunu değiştirmenin de native bir değişiklik olduğunu, yani güncelleme değil yeni bir build gerektirdiğini unutmayın.
Gerçek bir native modül kaçınılmaz olduğunda onu kendiniz yazar ve kod deponuzda (repo) tutarsınız; modül de geri kalan her şey gibi aynı prebuild ve EAS Build hattından geçer. OTA güncellemelerini, yönetilen yükseltmeleri ve iş akışının tamamını korursunuz. Bu altyapıda geçen yıllar boyunca uygulamalarımızdan çok azı gerçekten elle yazılmış native koda ihtiyaç duydu ve hiçbiri bunun için Expo'dan ayrılmak zorunda kalmadı.
Yeni Mimari artık varsayılan
React Native, çoğunlukla Yeni Mimari (New Architecture) olarak anılan, baştan yazılmış bir çekirdek yayınladı: Fabric renderer, JavaScript'in native tarafla eski asenkron köprü yerine C++ üzerinden konuşmasını sağlayan JSI katmanı, TurboModules ve Hermes motoru. Özetle: 0.76 ile birlikte Yeni Mimari tüm React Native projelerinde varsayılan olarak açık. Dokümantasyona göre de bu geçişten önce Meta'nın canlı uygulamalarında büyük ölçekte denenip kanıtlanmıştı.
Yukarıdaki tablodaki her uygulama bunu kullanıyor. Faydasını görmek için iç yapısını anlamanız gerekmez: daha hızlı açılış, daha akıcı listeler ve animasyonlar, üzerine yatırım yapılmaya devam eden bir temel. Kontrol etmeniz gereken şey, kullandığınız her native kütüphanenin bunu destekleyip desteklemediği, çünkü sizi geride tutma ihtimali en yüksek şey eskimiş, bakımı bırakılmış bir bağımlılıktır. İşe başlamadan önce bağımlılık listesini tam da bu açıdan denetliyoruz. Önerilen bir yükseltmenin bir sprint gecikmesinin en yaygın nedeni de bu.
Gerçek yayın sorunlarını en baştan ele almak
İlk Expo uygulamasını yayınlayan ekipleri dört şey tökezletir. Hiçbiri framework sorunu değil ve hepsi için önceden plan yapmak, sonradan keşfetmekten ucuza gelir.
App Store incelemesi. Expo uygulamaları sıradan native binary'lerdir, dolayısıyla diğer tüm uygulamalarla aynı kurallara tabidir. İncelemecilerin gerçekte takıldığı şeyler framework seçiminiz değil; hesap silme, net abonelik koşulları ve dürüst izin istemleridir. OTA güncellemeleri yukarıda anlatılan native olmayan ince ayarlar için uygundur. Özellik düzeyindeki değişiklikleri bu yolla yayınlamayarak güvende kalırsınız.
Native bağımlılıklar. Bir özelliği bir kütüphanenin üzerine kurmadan önce, bakımı süren bir config plugin'i ya da Expo uyumlu bir paketi olduğunu doğrulayın. Bunlardan yoksun bir bağımlılık, onuncu haftada değil birinci haftada yakalanması gereken bir uyarı işaretidir.
Config ve gizli anahtarlar. Anlık bildirim kimlik bilgileri, abonelik anahtarları ve API anahtarları, meraklı bir kullanıcının okuyabileceği JavaScript paketinin içine gömülmemeli, EAS ortam yapılandırmasında durmalı. Devraldığımız kod tabanlarında en sık gördüğümüz hata bu ve genellikle yanında bozuk bir ödeme ekranı da çıkıyor. Gelirinizin abonelikten geldiği bir uygulamada bu bağlantıyı ilk seferde doğru kurmaya değer: tüm yolu RevenueCat ve ödeme ekranı rehberimizde anlattık, abonelikli uygulama geliştirme işimizin omurgası da bu.
Gerçekten yayınladığınız build üzerinde test. Bir release build, geliştirme sunucusundan farklı davranır: küçültülmüş (minified) kod, gerçek native modüller, mağaza üzerinden gerçek ödemeler, fast refresh yok. Tablodaki uygulamalar için yüzden fazla akıştan oluşan bir Maestro uçtan uca test paketimiz var. Bu testleri geliştirme paketinde değil, release build'lerde çalıştırıyoruz, çünkü yakalamaya değer hatalar yalnızca binary'de ortaya çıkıyor. Aynı disiplin mağaza tarafı için de geçerli: metadata hattımız 25 yerel ayar (locale) için mağaza sayfalarını, 43 dil için bildirim metinlerini yayına gönderiyor. Bu iş ancak her pazar için elle yazılmak yerine betikle üretildiği için yönetilebilir.
Varsayılan tercihimiz: açık ve net
Çoğu girişim uygulaması için doğru seçim, EAS Build ve EAS Update ile birlikte bir Expo development build'dir. Farklı bir yol seçmek içinse sağlam bir gerekçe gerekir. Bu yapı size gerçek native yetenekler, bir Mac filosu kurmadan bulutta build, küçük işler için OTA düzeltmeleri ve sancısız framework yükseltmeleri sağlar. Native tarafa yalnızca bunu gerektiren belirli entegrasyon için inersiniz ve bunu iş akışından çıkmadan yaparsınız. Yazının başındaki tablodaki her uygulama tam olarak bu altyapıyla çalışıyor. Bu altyapı üzerinde sabit kapsam ve sabit takvimle çalışmak isterseniz React Native uygulama geliştirme hizmetimiz bu hat üzerine kurulu.
Sık sorulan sorular
Expo 2026'da canlı uygulamalar için hazır mı?
Evet. Eskiden asıl engel, sabit bir native modül setiyle Expo Go'nun içinde sıkışıp kalmaktı ve development build'ler bunu çözdü. Development build, tamamen sizin kontrolünüzde olan gerçek bir native binary'dir. İstediğiniz native kütüphaneyi ekleyebilir, iki mağazaya da yayınlayabilir ve Yeni Mimari (New Architecture) üzerinde çalıştırabilirsiniz. Kendi abonelikli uygulamalarımızı App Store ve Play Store'da bu altyapıyla çalıştırıyoruz.
Expo'dan hâlâ "eject" etmem gerekir mi?
Hayır, üstelik "eject" diye bir kavram artık pek kalmadı. Continuous Native Generation (CNG) sayesinde native klasörleriniz gerektiğinde config ve config plugin'lerden üretiliyor, yani build'inizin sahibi zaten sizsiniz. Özel native koda ihtiyaç duyduğunuzda aynı projenin içine bir native modül ya da config plugin eklersiniz ve iş akışının tüm avantajlarını korursunuz.
EAS Build ile EAS Update arasındaki fark nedir?
EAS Build, iOS ve Android için gerçek, imzalı uygulama dosyalarını bulutta üretir; mağazalara gönderdiğiniz dosya budur. EAS Update ise yüklü bir uygulamanın native olmayan kısımlarına, yani JavaScript'e, stillere ve asset'lere OTA (over-the-air) değişiklik gönderir. Native değişiklikler, izin değişiklikleri ve SDK yükseltmeleri yeni bir EAS Build ve yeni bir mağaza gönderimi gerektirir.
EAS Update'im neden kullanıcılarıma hiç ulaşmadı?
Sebep neredeyse her zaman runtimeVersion uyuşmazlığıdır. Bir güncelleme yalnızca runtime sürümü, güncellemenin yayınlandığı sürümle eşleşen build'lere ulaşır, çünkü güncellemeyle build'in native kodunun uyumlu olmasını garanti eden şey runtime sürümüdür. Eğer appVersion politikasını kullanıyorsanız mağazaya 1.4.0'ı göndermek yüklü kitlenizi ikiye böler ve 1.4.0 için yayınlanan bir güncelleme hâlâ 1.3.x'te kalan hiç kimseye ulaşmaz. Runtime sürümünü bilinçli olarak sabitleyin ve suçu güncellemeye atmadan önce build'in içine gerçekte hangi değerin gömüldüğünü kontrol edin.
Yeni bir uygulama hangi Expo SDK'siyle başlamalı?
En yeniyle, yerine koyamayacağınız bir bağımlılık geride kalmadıysa. Güncel sürümle başlarsanız zorunlu bir yükseltmeye kadar en uzun süreyi kazanırsınız. Canlı uygulamalarımız en yeni sürümün sıfır ila üç SDK sürümü gerisinde çalışıyor. Bu, zaten gelir getiren uygulamalar için bilinçli bir tercih, bugün başlayan bir proje için öneri değil.
Expo uygulamaları React Native'in Yeni Mimarisini kullanabilir mi?
Evet. Yeni Mimari, 0.76'dan beri yeni React Native projelerinde varsayılan olarak açık ve Expo bunu destekliyor. Doğrulamanız gereken tek şey native bağımlılıklarınızın uyumlu olması, çünkü bir ekibin geçişi ertelemek zorunda kalmasının en yaygın nedeni bakımı bırakılmış bir kütüphanedir.
Expo yerine ne zaman bare React Native seçmeliyim?
Nadiren, o da genellikle çok belirli bir nedenle: config plugin'i olmayan derin bir native entegrasyon ya da genişlettiğiniz büyük bir mevcut native kod tabanı. O durumda bile çoğu ekip için yönetilen yükseltmelerden ve OTA güncellemelerinden vazgeçmektense Expo projesinin içine bir native modül eklemek daha iyi sonuç verir. Development build ile başlayın; ondan bir söylenti yüzünden değil, ancak gerçek bir kısıt yüzünden vazgeçin.
Kaynaklar
- Expo dokümanları: development build'ler
- Expo dokümanları: EAS Build
- Expo dokümanları: EAS Update
- Expo dokümanları: runtime sürümleri
- Expo dokümanları: config plugin'ler
- Expo dokümanları: Continuous Native Generation (CNG)
- Expo dokümanları: SDK sürümleri ve React Native uyumluluğu
- React Native dokümanları: Yeni Mimari
Bunu sizin için geliştirmemizi ister misiniz? 30 dakikalık görüşme planlayın.
Blogdan diğer yazılar
Uygulamanıza yapay zeka ajanı nasıl eklenir: mimari ve maliyet
Mobil uygulamanıza yapay zeka ajanı eklemek için kurulum ve maliyet rehberi: araç kullanım döngüsü, güvenli backend ve aylık faturayı tahmin etme yolu.
Uygulamaya abonelik ekleme: RevenueCat ve paywall rehberi
RevenueCat ile React Native uygulamasına abonelik ekleme: entitlement, offering, webhook, paywall zamanlaması ve sandbox testleri.
Uygulama fikriniz için MVP kapsamı nasıl belirlenir
Uygulama fikrinizi yayına hazır bir MVP'ye dönüştürün: tek çekirdek döngüyü bulun, olmazsa olmazları ayırın, kapsamı süre ve maliyete bağlayın.