EAS Update: Aggiornamenti OTA in React Native con Expo nel 2026

EAS Update pubblica aggiornamenti JavaScript in React Native senza passare dalla review degli store. Ecco come configurarlo, gestire runtime fingerprint, canali, rollback e CI/CD nel 2026.

EAS Update OTA React Native (2026)

Aggiornato: 8 agosto 2026

EAS Update è il servizio di aggiornamenti over-the-air (OTA) di Expo che ti permette di pubblicare modifiche a JavaScript, asset e configurazione di un'app React Native senza dover ricompilare il binario nativo o passare da una nuova review degli app store. Nel 2026, con l'arrivo dei fingerprint automatici, la maturità dei canali branch-based e l'integrazione ufficiale con GitHub Actions, è diventato lo strumento standard per iterare rapidamente in produzione mantenendo il pieno controllo sulla compatibilità con il runtime nativo. In questa guida vedrai come configurarlo, pubblicare aggiornamenti sicuri, gestire rollback e integrare il flusso nella tua pipeline CI/CD.

  • EAS Update distribuisce aggiornamenti JavaScript, asset e configurazione in pochi secondi tramite CDN, evitando la review degli app store per fix e piccole feature.
  • Il runtimeVersion definisce la compatibilità tra bundle JS e binario nativo; nel 2026 il valore consigliato è {"policy": "fingerprint"}, che calcola automaticamente un hash del layer nativo.
  • I channel collegano le build native (production, staging, preview) ai branch di aggiornamento, permettendo di ruotare tra versioni senza rebuild.
  • Il rollback si effettua ripubblicando un update precedente con eas update:republish o azzerando il branch con eas update:roll-back-to-embedded.
  • Le regole di Apple e Google consentono OTA solo per contenuti coerenti con la funzionalità dichiarata al momento della review; modifiche sostanziali richiedono una nuova build.
  • La CLI eas-cli 16+ integra i workflow GitHub Actions ufficiali e supporta il code signing per firmare gli update contro manomissioni.

Cos'è EAS Update e come funziona

EAS Update è un servizio di hosting e distribuzione di update JavaScript per app React Native basate su Expo. Ad ogni pubblicazione, la CLI carica su un CDN globale il bundle JS compilato con Hermes, tutti gli asset referenziati (immagini, font, JSON) e un manifest firmato che descrive quale build nativa può caricarli. All'avvio, l'app usa il modulo expo-updates per contattare il server, confrontare il proprio runtimeVersion con quello dell'update disponibile e, se compatibile, scaricare e applicare la nuova versione. Di default, l'applicazione avviene al successivo cold start, oppure immediatamente tramite l'API imperativa.

La chiave dell'architettura è la separazione tra layer nativo (compilato in un file .ipa o .aab) e layer JavaScript (aggiornabile via OTA). Finché il codice nativo non cambia (non aggiungi librerie con codice Kotlin/Swift, non modifichi Info.plist o AndroidManifest.xml, non passi a una nuova SDK Expo) puoi rilasciare modifiche in produzione in pochi secondi. È il meccanismo che alimenta il flusso "web-like" tanto amato dai team che vengono dal frontend, e nel 2026 rimane l'unico modo ufficialmente supportato da Expo per ridurre il ciclo di iterazione post-release.

Configurare expo-updates in un progetto React Native

Ok, mettiamoci al lavoro. La configurazione richiede un progetto Expo (managed o bare) collegato a un account EAS. Se parti da zero, installa la CLI e autenticati.

npm install -g eas-cli
eas login
cd my-app
npx expo install expo-updates
eas init
eas update:configure

Il comando eas update:configure aggiunge automaticamente le sezioni necessarie ad app.json: l'URL del server di update, la projectId e il runtimeVersion. Il risultato tipico è simile a questo.

{
  "expo": {
    "name": "MyApp",
    "slug": "my-app",
    "runtimeVersion": { "policy": "fingerprint" },
    "updates": {
      "url": "https://u.expo.dev/00000000-0000-0000-0000-000000000000",
      "enabled": true,
      "checkAutomatically": "ON_LOAD",
      "fallbackToCacheTimeout": 0
    },
    "extra": {
      "eas": {
        "projectId": "00000000-0000-0000-0000-000000000000"
      }
    }
  }
}

Nel workflow bare, oltre a installare il pacchetto, occorre eseguire npx pod-install e verificare che Podfile includa use_expo_modules!. Su Android, il plugin Gradle di expo-updates viene aggiunto automaticamente da expo-modules-autolinking. Prima di procedere è utile controllare che le build EAS siano configurate correttamente: la nostra guida a EAS Build e Submit descrive nel dettaglio come impostare i profili di build che consumeranno gli update.

Come pubblicare il primo aggiornamento OTA

Prima di pubblicare un update, l'utente deve avere un binario nativo installato che punta allo stesso server EAS. Crea una build interna per test.

eas build --profile preview --platform all

Una volta installata la build sul dispositivo o sul simulatore, modifica un qualsiasi file JavaScript (per esempio cambia il testo della schermata principale) e pubblica un update.

# Pubblica sul branch "preview" con un messaggio descrittivo
eas update --branch preview --message "Cambiato il titolo della home"

La CLI compila il bundle Hermes, calcola il fingerprint del progetto, carica gli asset e stampa un URL di anteprima e un QR code. Riavvia due volte l'app: al primo lancio l'update viene scaricato in background, al secondo viene applicato. Se vuoi forzare il download immediato durante lo sviluppo, usa l'API imperativa nel codice.

import * as Updates from 'expo-updates';

async function checkForUpdates() {
  try {
    const update = await Updates.checkForUpdateAsync();
    if (update.isAvailable) {
      await Updates.fetchUpdateAsync();
      // Applica immediatamente e riavvia l'app
      await Updates.reloadAsync();
    }
  } catch (error) {
    console.warn('Errore durante il check OTA:', error);
  }
}

Questa funzione tipicamente si invoca al ritorno in foreground (cambio di AppState ad active), non al primo mount, per non allungare il tempo di avvio. Se ti interessa capire l'impatto sul TTI, abbiamo un approfondimento dedicato all'ottimizzazione del cold start in React Native.

Runtime version e fingerprint nel 2026

Il runtimeVersion è il patto tra bundle JavaScript e binario nativo. Se i due valori non coincidono, l'update viene ignorato e l'app carica il bundle embedded. È esattamente ciò che protegge gli utenti da un JS che chiama un metodo nativo inesistente. Nel 2026, le policy supportate sono quattro:

  • fingerprint: expo-updates calcola un hash SHA-256 di tutti i file che influenzano la build nativa (config plugin, native modules, versione delle dipendenze). Cambia solo quando cambia davvero il layer nativo. È la scelta di default consigliata da SDK 51 in poi.
  • appVersion: usa il campo version di app.json. Semplice ma richiede disciplina, perché va bumpata a ogni release nativa.
  • sdkVersion: usa la versione dell'SDK Expo. Sconsigliato per team che aggiungono moduli custom.
  • Valore esplicito: una stringa fissa (es. "1.0.0"). Massimo controllo, massima responsabilità.

Onestamente, la policy fingerprint risolve il problema più frequente degli OTA. Nel mio ultimo progetto mi era già capitato di dimenticare di bumpare la versione dopo aver aggiunto una libreria nativa, e per una notte intera abbiamo servito JS incompatibile a utenti su una build vecchia (fortunatamente in staging). Con il fingerprint quel JS finisce automaticamente su un runtime diverso e non raggiunge mai la build precedente. Puoi verificare il valore corrente con npx expo-updates fingerprint:generate. Per i dettagli sulle regole di invalidazione, la documentazione ufficiale di Expo sulle runtime versions è il riferimento autorevole.

Canali, branch e ambienti multipli

EAS Update separa il concetto di channel (proprietà della build nativa, impostata al momento del build) e di branch (etichetta lato server a cui punta un channel). Un channel può essere ricollegato a un branch diverso in qualsiasi momento senza rebuild. È il meccanismo che rende possibile promuovere staging in produzione con un solo comando.

Configura i profili in eas.json.

{
  "build": {
    "preview": {
      "distribution": "internal",
      "channel": "preview"
    },
    "staging": {
      "channel": "staging"
    },
    "production": {
      "channel": "production",
      "autoIncrement": true
    }
  }
}

Con questa configurazione, pubblichi update separati per ciascun ambiente.

eas update --branch staging --message "Beta della feature Checkout v2"
eas update --branch production --message "Fix crash sul filtro categorie"

Per promuovere un update da staging a produzione senza ripubblicare, usa il comando di republish.

# Promuove l'update più recente di staging su production
eas update --branch production --republish --group <GROUP_ID>

Il GROUP_ID lo trovi con eas update:list --branch staging. Questo pattern (tre channel, tre branch, promozione esplicita) è ormai lo standard nei team che rilasciano più volte a settimana ed è il modo più naturale per far coesistere QA interno, beta esterna e produzione.

Rollback e strategie di rilascio graduale

Un OTA che rompe l'app in produzione è uno degli scenari peggiori. L'utente non può ricevere fix finché non riavvia l'app, e in casi estremi non riesce nemmeno ad aprirla. EAS Update offre due meccanismi principali di rollback.

Il primo è ripubblicare un update precedente, il modo più veloce quando l'ultimo release ha introdotto un bug.

eas update:list --branch production
# Copia il GROUP_ID dell'update stabile precedente
eas update --branch production --republish --group <GROUP_ID> \
  --message "Rollback a versione stabile"

Il secondo è il rollback all'embedded bundle, cioè al JS spedito insieme al binario nativo. È utile quando anche gli update precedenti sono compromessi.

eas update:roll-back-to-embedded --branch production \
  --message "Rollback all'embedded per bug critico"

Questo comando pubblica un update speciale che istruisce l'app a caricare il bundle embedded ignorando qualsiasi altro update fino a nuovo ordine. È la rete di sicurezza definitiva. Per un rilascio graduale, invece, EAS Update supporta il rollout progressivo lato server: passi la flag --rollout-percentage per esporre l'update solo a una percentuale del traffico e aumenti gradualmente il valore osservando le metriche.

eas update --branch production --message "Nuovo onboarding" \
  --rollout-percentage 10
# Se le metriche sono sane, aumenta
eas update:edit --rollout-percentage 50
eas update:edit --rollout-percentage 100

Integrare EAS Update con GitHub Actions

Automatizzare la pubblicazione è essenziale per avere un flusso ripetibile. Expo mantiene la action ufficiale expo-github-action che installa eas-cli, gestisce l'autenticazione tramite EXPO_TOKEN e supporta il caching delle node_modules.

name: EAS Update

on:
  push:
    branches: [main]

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm

      - uses: pnpm/action-setup@v3
        with:
          version: 9

      - uses: expo/expo-github-action@v8
        with:
          expo-version: latest
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}

      - run: pnpm install --frozen-lockfile

      - name: Publish OTA update
        run: eas update --branch production --message "${{ github.event.head_commit.message }}" --non-interactive

Per generare il token, vai su expo.dev/accounts/<team>/settings/access-tokens e crea un bot user con permessi minimi (solo update publish). Non usare mai il tuo token personale in CI. Se lavori con più repository correlati, considera anche un approccio monorepo: la nostra guida a monorepo React Native con pnpm e Turborepo mostra come condividere lo stesso workflow tra app e librerie interne.

Regole degli app store e best practice

EAS Update è pienamente compatibile con le linee guida di Apple e Google, ma con vincoli precisi da rispettare. Apple ammette gli aggiornamenti OTA solo se il codice pubblicato è JavaScript interpretato (o compilato con Hermes) e non modifica funzionalità o scopi principali dichiarati durante la review. La regola 3.3.1 del Developer Program License Agreement e la 4.7 delle App Store Review Guidelines sono i riferimenti; violarle espone al rischio di rimozione dallo store. Google Play, dal canto suo, applica un principio analogo tramite la sezione Device and Network Abuse del Google Play Developer Program Policy.

Ecco un elenco di best practice consolidate nel 2026.

  1. Usa la fingerprint policy. Elimina intere classi di bug legati a mismatch nativo/JS.
  2. Firma i tuoi update con code signing. eas update:configure --code-signing genera una coppia di chiavi ECDSA e obbliga l'app a rifiutare update non firmati con la chiave attesa.
  3. Monitora ogni update. Tagga gli eventi Sentry/Datadog con Updates.updateId e crea alert sui picchi di errori nelle prime ore.
  4. Non pubblicare direttamente su production. Sempre staging prima, con test su dispositivi reali.
  5. Documenta ogni release. I message di update sono visibili nel dashboard e sono la tua storia. Sii esplicito ("Fix crash iOS 18 sul filtro"), non generico ("piccoli fix").
  6. Non spedire feature intere via OTA. Se una modifica è grossa e meritevole di release note store, va in una nuova build. Gli OTA sono per iterazione fine e correzione, non per aggirare la review.
  7. Coordina i changelog con il team di prodotto. Un update pubblicato senza avvisare l'assistenza clienti finisce inevitabilmente in ticket "l'app è cambiata".

Infine, ricorda che EAS Update ha un piano gratuito generoso ma non illimitato: 1.000 utenti attivi mensili di update e larghezza di banda inclusa. Per app in produzione con centinaia di migliaia di utenti, il piano Production include update illimitati e SLA. Controlla i dettagli nella pagina prezzi ufficiale di Expo.

Domande frequenti

Qual è la differenza tra EAS Update e CodePush di Microsoft?

CodePush è stato deprecato a marzo 2025 e verrà spento definitivamente entro il 2026. EAS Update è il successore de facto per progetti React Native e Expo: offre CDN globale, code signing, fingerprint automatico dei runtime, integrazione nativa con EAS Build e con il dashboard Expo. La migrazione da CodePush richiede di sostituire react-native-code-push con expo-updates e di ripubblicare una build nativa.

Quanto costa EAS Update in produzione?

Il piano gratuito include 1.000 MAU (monthly active users) di update e larghezza di banda proporzionale. Il piano Production a partire da 99 $/mese include update illimitati, SLA e priority support. Se superi la soglia gratuita ti viene addebitato l'overage al costo per MAU documentato sulla pagina pricing di Expo, e in genere resta più economico che gestire un proprio CDN con server di manifest.

Posso usare EAS Update senza Expo, con un progetto React Native puro?

Sì. Il modulo expo-updates funziona anche in progetti bare React Native, purché sia installato via expo-modules-autolinking e configurato manualmente in app.json con projectId e url. Non è necessario adottare tutto l'ecosistema Expo: puoi mantenere il tuo codice nativo custom e usare solo il servizio di update.

Un aggiornamento OTA viene applicato immediatamente all'utente?

Di default no. expo-updates scarica l'update in background al primo avvio e lo applica al successivo cold start. È il comportamento consigliato per non interrompere la sessione. Per applicarlo immediatamente devi chiamare Updates.fetchUpdateAsync() seguito da Updates.reloadAsync(), ma valuta bene l'impatto UX: un reload improvviso mentre l'utente sta compilando un form è una regressione, non un miglioramento.

Come posso testare un update OTA prima di pubblicarlo agli utenti?

Usa un branch dedicato (es. preview o staging) collegato a un profilo di build interno distribuito solo al team via TestFlight o Google Play Internal Testing. Pubblica lì l'update, verifica su dispositivi reali per almeno 24 ore, poi promuovi con eas update --branch production --republish --group <ID>. In alternativa, per un feedback ancora più rapido, il QR code stampato da eas update apre l'update in Expo Go o in una development build senza dover rilasciare nulla.

Sull'Autore Editorial Team

Our team of expert writers and editors.