v0.32.0
Content-Addressed Storage
Bundle diffing in 0.31.0 made OTA downloads smaller for devices, but deploys still uploaded every asset for every release. That meant unchanged assets could be sent to the same storage over and over, making deploys slower and more expensive than they needed to be.
With content-addressed storage, Hot Updater now stores manifest assets under deterministic keys derived from their content hash. During deploy, assets with the same content are deduplicated, and objects that already exist in storage are skipped instead of uploaded again.
The first deploy after moving to the new storage layout may still take longer because all existing assets need to be uploaded once. After that, deploys upload only the files that actually need to be stored.
No special deploy command is required. After your server code is refreshed, deploy OTA updates as usual.
Android Native Config Uses Manifest Metadata
Android Hot Updater native config values are now written to AndroidManifest.xml <meta-data> instead of strings.xml.
These values are runtime identifiers, not user-facing text. When they lived in strings.xml, Android resource localization could translate them. For example, a release build on a Turkish device could read the production channel as üretim, causing the client to check the wrong update channel and return UP_TO_DATE.
The Android runtime now reads manifest metadata first and keeps legacy strings.xml values as a fallback, so existing apps can continue to work while newly generated native config avoids localized resource values.
Cloudflare R2 Storage Uses the S3 API
Cloudflare r2Storage now uses the R2 S3-compatible API for deploy-time storage operations. The previous R2 storage path was too slow for repeated asset uploads, especially with larger bundles or many assets.
Because this storage path uses the S3-compatible API, Cloudflare R2 credentials are now required. We recommend creating them from the Cloudflare dashboard and using the generated access key and secret for your Hot Updater configuration.
d1Database is unchanged. Only the R2 storage side needs the new credentials.
Expo Fingerprint as an Optional Peer
@expo/fingerprint is now loaded as an optional peer dependency instead of being bundled into hot-updater.
Projects that use the fingerprint update strategy should install @expo/fingerprint in the app project:
pnpm add -D @expo/fingerprintUse the equivalent install command for your package manager if you do not use pnpm. This avoids Expo Doctor warnings caused by hot-updater carrying Expo fingerprint internally, while fingerprint commands still give a direct install hint when the package is missing.
Migration Guide
- Upgrade
hot-updaterand every@hot-updater/*package to0.32.0. - Refresh the generated server or infrastructure code:
npx hot-updater init- Redeploy the refreshed server or infrastructure so it can resolve the new content-addressed asset paths.
- For Android apps, refresh your native config so Hot Updater writes values to
AndroidManifest.xmlmetadata. Existingstrings.xmlvalues remain supported as a fallback. - If you use Cloudflare
r2Storage, create R2 S3 API credentials from the Cloudflare dashboard and add them to your Hot Updater configuration.d1Databasedoes not need to change. - If your project uses the fingerprint update strategy, install
@expo/fingerprintin the app project.
No database migration is required. For content-addressed storage, the required migration is the server code refresh; the React Native SDK/runtime does not need a special deploy command.
What's Changed
- feat(cli): check native OTA wiring in
hot-updater doctorby @gronxb in #1001 - chore: update versions by @github-actions[bot] in #1002
- chore(cli): bundle hot-updater CLI-only dependencies by @gronxb in #1005
- chore(cli): tree-shake sql-formatter dialects by @gronxb in #1006
- chore: update versions by @github-actions[bot] in #1007
- fix(hot-updater): match patch bases by semver compatibility by @gronxb in #1008
- chore: update versions by @github-actions[bot] in #1009
- fix(android): mark channel string non-translatable by @MidnightCoke in #1011
- chore: update versions by @github-actions[bot] in #1012
- fix(android): avoid localized native config values by @gronxb in #1017
- chore: harden OTA management and bundle path handling by @gronxb in #1003
- feat(supabase): harden Supabase init with RLS by @gronxb in #1019
- fix(hot-updater): load Expo fingerprint as optional peer by @gronxb in #1021
- feat(hot-updater): content-addressable storage by @gronxb in #1014
- chore: update versions by @github-actions[bot] in #1018
New Contributors
- @MidnightCoke made their first contribution in #1011
Full Changelog: v0.31.0...v0.32.0