Minimal, headless React Native hot update library.
npm install @take-out/native-hot-updateMinimal, headless React Native hot update library.
- Simple instance-based API
- Pluggable storage (MMKV, AsyncStorage, custom)
- Timeout protection (5s + 20s hard limit)
- Pre-release testing workflow
- Works with Expo & React Native
- Zero UI - bring your own components
``bash`
bun add @take-out/native-hot-update react-native-mmkv
`ts
// src/hotUpdater.ts
import { MMKV } from 'react-native-mmkv'
import { createHotUpdater } from '@take-out/native-hot-update'
import { createMMKVStorage } from '@take-out/native-hot-update/mmkv'
const mmkv = new MMKV({ id: 'hot-updater' })
const hotUpdaterInstance = createHotUpdater({
serverUrl: 'https://your-update-server.com',
storage: createMMKVStorage(mmkv),
updateStrategy: 'appVersion',
})
// Export the hook and instance
export const useOtaUpdater = hotUpdaterInstance.useOtaUpdater
export const hotUpdater = hotUpdaterInstance
`
`tsx
// app/index.tsx or App.tsx
import { HotUpdater } from '@take-out/native-hot-update'
function App() {
// Your app component
return
}
// IMPORTANT: wrap() initializes HotUpdater config - required for checkForUpdate
export default HotUpdater.wrap({
baseURL: 'https://your-update-server.com',
updateMode: 'manual', // Use manual mode with custom hooks
})(App)
`
> Note: For custom server implementations, you can use resolver instead ofbaseURL
> . See advanced usage below.
`tsx
// app/_layout.tsx
import { useOtaUpdater } from './hotUpdater'
export default function RootLayout() {
const { userClearedForAccess, progress } = useOtaUpdater({
enabled: true,
onUpdateDownloaded: (info) => {
console.info('Update downloaded:', info.id)
},
onError: (error) => {
console.error('Update failed:', error)
},
})
if (!userClearedForAccess) {
return
}
return
}
`
`tsx
import { hotUpdater } from './hotUpdater'
import * as Application from 'expo-application'
export function VersionDisplay() {
const otaId = hotUpdater.getShortOtaId()
const channel = hotUpdater.getChannel()
return (
v{Application.nativeApplicationVersion}
{otaId && (${otaId})} • {channel}
)
}
`
`tsx
import { hotUpdater } from './hotUpdater'
import { Button, View, Text, Alert } from 'react-native'
export function DevUpdateTools() {
const handleCheckUpdate = async () => {
const update = await hotUpdater.checkForUpdate()
if (update) {
Alert.alert('Update available', ID: ${update.id}, [
{ text: 'Later' },
{ text: 'Reload', onPress: () => hotUpdater.reload() },
])
} else {
Alert.alert('No update available')
}
}
const handleCheckPreRelease = async () => {
const update = await hotUpdater.checkForUpdate({
channel: 'production-pre',
isPreRelease: true,
})
if (update) {
Alert.alert('Pre-release available', ID: ${update.id}, [
{ text: 'Later' },
{ text: 'Reload', onPress: () => hotUpdater.reload() },
])
}
}
return (
)
}
`
Creates a hot updater instance.
Config:
- serverUrl (string): Your hot update server URLstorage
- (HotUpdateStorage): Storage adapter for persisting stateupdateStrategy
- ('appVersion' | 'fingerprint'): Update strategy (default:
'appVersion')
Returns: HotUpdaterInstance
React hook for automatic update checking.
Options:
- enabled (boolean): Enable/disable update checking (default: true)onUpdateDownloaded
- (function): Callback when update is downloadedonError
- (function): Callback on error
Returns:
- userClearedForAccess (boolean): Whether user can access appprogress
- (number): Download progress (0-100)isUpdatePending
- (boolean): Whether update will apply on restart
- checkForUpdate(options?) - Manually check for updatesgetAppliedOta()
- - Get current OTA bundle IDgetShortOtaId()
- - Get short OTA IDgetIsUpdatePending()
- - Check if update is pendingreload()
- - Reload appgetBundleId()
- - Get current bundle IDgetMinBundleId()
- - Get minimum bundle IDgetChannel()` - Get current channel
-