β Self-hosted update distribution system
Typescript Only, Zero kotlin, Zero Swift, Zero java, Zero Object-C
2025-05-21.9.45.54.mp4
You can find the full usage guide and API reference in the
π Cloud Push Docs
Expo projects are highly customized React Native projects. Because of this, available CodePush solutions are limited.
This project, inspired by hot-updater
, offers an alternative way to manage bundles using storage services like S3, Firebase, Supabase, etc.
It follows Expo Updates technical specs and maintains compatibility with Expo Updates.
- β
Works with
expo run:android --variant release
- β
Works with
expo run:ios --configuration Release
- β Compatible with Expo Managed Workflow
- π‘ Self-hosted deployment supported
- π¦ Flexible storage & DB (S3, Supabase, Firebase, etc.)
- π Compatible with Expo Updates APIs
- πΎ Web-based bundle version dashboard
- π Supports expo.dev environment variables (via EAS Secrets)
- πͺ Works on Windows
- π§ͺ EAS build supported
import { defineConfig } from "@cloud-push/cli";
import { SupabaseStorageClient, SupabaseDbClient } from "@cloud-push/cloud";
export default defineConfig(() => ({
loadClients: () => {
const storageClient = new SupabaseStorageClient({
bucketName: process.env.SUPABASE_BUCKET_NAME!,
supabaseUrl: process.env.SUPABASE_URL!,
supabaseKey: process.env.SUPABASE_KEY!,
});
const dbClient = new SupabaseDbClient({
tableName: process.env.SUPABASE_TABLE_NAME!,
supabaseUrl: process.env.SUPABASE_URL!,
supabaseKey: process.env.SUPABASE_KEY!,
});
return {
storage: storageClient,
db: dbClient,
};
},
}));
import { defineConfig } from "@cloud-push/cli";
import { AWSS3StorageClient, LowDbClient } from "@cloud-push/cloud";
export default defineConfig(() => ({
loadClients: () => {
const storageClient = new AWSS3StorageClient({
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
bucketName: process.env.AWS_BUCKET_NAME!,
region: process.env.AWS_REGION!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
});
const dbClient = new LowDbClient({
downloadJSONFile: () => storageClient.getFile({ key: "cursor.json" }),
uploadJSONFile: (file: Uint8Array) =>
storageClient.uploadFile({ key: "cursor.json", file }),
});
return {
storage: storageClient,
db: dbClient,
};
},
}));
import { defineConfig } from "@cloud-push/cli";
import { FirebaseStorageClient, FirebaseDbClient } from "@cloud-push/cloud";
export default defineConfig(() => ({
loadClients: () => {
const storageClient = new FirebaseStorageClient({
credential: process.env.FIREBASE_CREDENTIAL!,
bucketName: process.env.BUCKET_NAME!,
});
const dbClient = new FirebaseDbClient({
credential: process.env.FIREBASE_CREDENTIAL!,
databaseId: process.env.FIREBASE_DATABASE_ID!,
});
return {
storage: storageClient,
db: dbClient,
};
},
}));
Constant | Supported |
---|---|
Updates.channel |
β |
Updates.checkAutomatically |
β |
Updates.createdAt |
β |
Updates.emergencyLaunchReason |
β³ |
Updates.isEmbeddedLaunch |
β |
Updates.isEmergencyLaunch |
β³ |
Updates.isEnabled |
β |
Updates.latestContext |
β |
Updates.launchDuration |
β |
Updates.manifest |
β |
Updates.runtimeVersion |
β |
Updates.updateId |
β |
Hook | Supported |
---|---|
useUpdates() |
β |
Method | Supported |
---|---|
checkForUpdateAsync() |
β |
clearLogEntriesAsync() |
β |
fetchUpdateAsync() |
β |
getExtraParamsAsync() |
β |
readLogEntriesAsync() |
β |
reloadAsync() |
β |
setExtraParamAsync() |
β |