@upfluxhq/cli
v1.1.0
Published
Upflux CLI for managing OTA updates
Readme
@upfluxhq/cli
Command-line interface for managing Upflux OTA updates for React Native and Capacitor apps.
Installation
npm install -g @upfluxhq/cli
# or
pnpm add -g @upfluxhq/cliQuick Start
# 1. Authenticate with your publish keys (supports multiple!)
upflux login --key <staging-publish-key>
upflux login --key <production-publish-key>
# 2. Upload a release (will prompt if multiple deployments)
upflux release --label v1.0.0 --mandatory
# 3. Check release status
upflux statusCommands
login
Authenticate with the Upflux server. Supports multiple credentials - each login adds a new deployment.
upflux login --key <publishKey>| Option | Description |
|--------|-------------|
| -k, --key <publishKey> | Publish key for authentication |
Example output with multiple logins:
🔐 Verifying with server...
✓ Login successful!
App ID: app-970384d3
Deployment: production
Stored credentials (2):
→ 1. production (app-970384d3)
2. staging (app-970384d3)logout
Remove stored credentials.
upflux logout [options]| Option | Description |
|--------|-------------|
| --all | Remove all credentials |
Example:
# Interactive selection to remove one
upflux logout
# Remove all credentials
upflux logout --allrelease
Bundle and upload a new release. Prompts to select deployment if multiple are stored.
Automatically detects project type:
- React Native: Uses
react-native bundlecommand - Capacitor: Zips the web directory (detected via
capacitor.config.*)
upflux release [options]| Option | Required | Description |
|--------|----------|-------------|
| -l, --label <label> | ✓ | Release label (e.g., v1.0.0) |
| --platform <platform> | | Target platform: all, ios, or android (defaults to all) |
| -a, --app <appId> | | Application ID (auto-detected from credentials) |
| -d, --deployment <deploymentId> | | Deployment ID (prompts if multiple) |
| -e, --entry-file <path> | | Entry file for bundler (default: index.js) |
| -o, --output-dir <path> | | Output directory for bundle (default: ./dist) |
| -b, --bundle <path> | | Skip bundling, use existing bundle file |
| --assets <paths...> | | Skip auto-detection, use these asset files |
| -m, --mandatory | | Mark update as mandatory |
| -r, --rollout <number> | | Rollout percentage (0-100, default: 100) |
| -v, --version-range <range> | | Binary version range (e.g., >=1.0.0) |
| --min-binary-version <version> | | Minimum native binary version required. Devices below this are directed to update from the App Store / Play Store before receiving this OTA. |
| --skip-native-check | | Skip automatic native change detection (useful in CI/CD) |
| --dev | | Create development bundle |
| --skip-bundle | | Skip bundling, use existing files in output dir |
| --schedule | | Create as draft, set schedule time in dashboard |
| --capacitor | | Force Capacitor mode (auto-detected if capacitor.config exists) |
| --web-dir <path> | | Web directory to bundle for Capacitor (default: from config or www) |
Examples:
# Release to selected deployment (prompts if multiple)
upflux release --label v1.2.0
# iOS-only hotfix
upflux release --label v1.2.1-ios-fix --platform ios
# Android-only release with 50% rollout
upflux release --label v1.2.2 --platform android --rollout 50
# Mandatory update for all platforms
upflux release --label v1.3.0 --mandatory
# Schedule release (draft mode)
upflux release --label v1.4.0 --schedule
# Capacitor project with custom web directory
upflux release --label v1.0.0 --capacitor --web-dir distExample output:
📦 Bundling for iOS...
✓ iOS bundle created
📦 Bundling for Android...
✓ Android bundle created
⬆ Uploading release...
App: app-970384d3
Deployment: 6933e683aa32fe18a1311bbb
Deployment Name: production
Label: v1.2.0
Platform: all
Bundle: ./dist/ios/index.ios.bundle
Assets: 24 file(s)
Rollout: 100%
Mandatory: No
📋 Step 1/3: Requesting upload URLs...
✓ Got 26 presigned URLs
📤 Step 2/3: Uploading files directly to storage...
[1/26] index.ios.bundle
...
✓ Uploaded 26 files
✅ Step 3/3: Confirming release...
✓ Release uploaded successfully!
──────────────────────────────────
ID: 693507a19f6d6a79267633e8
Label: v1.2.0
iOS Bundle: uploaded
Android Bundle: uploaded
Rollout: 100%
Mandatory: No
Status: active
──────────────────────────────────Native Change Detection
The CLI automatically detects native code changes since your last release and warns you when a store update may be required. This helps prevent devices from receiving OTA updates that depend on native features not yet available in their installed binary.
How It Works
- After each successful release, the CLI saves the current git commit hash to
.upflux. - On the next release, it runs
git diff <lastHash>..HEADagainst native files. - If changes are found, it warns you and offers to auto-set
--min-binary-version.
Note: Detection requires git. If the project is not a git repo, detection is silently skipped.
Files Watched
| File | What is detected |
|---|---|
| android/app/build.gradle | versionName bump, minSdkVersion change |
| android/app/src/main/AndroidManifest.xml | New permissions |
| ios/Podfile | New native pods |
| ios/Podfile.lock | Any pod version change |
| package.json | New native dependency packages |
Example Interaction
⚠️ Native changes detected since last release:
Android:
• build.gradle: versionName → 2.0.0
• AndroidManifest.xml: New permission: android.permission.CAMERA
💡 Suggested flags:
--min-binary-version 2.0.0
--version-range ">=2.0.0"
? How would you like to handle these native changes?
❯ Auto-apply suggested flags (--min-binary-version 2.0.0 --version-range ">=2.0.0")
Enter min-binary-version manually
Continue without (not recommended for native changes)Setting --min-binary-version Manually
# Require devices to have at least v2.0.0 binary before receiving this OTA
upflux release --label v2.0.0-ota --min-binary-version 2.0.0 --version-range ">=2.0.0"Skipping in CI/CD
# In CI, skip interactive detection and pass flag explicitly
upflux release --label v2.0.0 --min-binary-version 2.0.0 --skip-native-checkstatus
Check deployment status and recent releases.
upflux status [options]| Option | Description |
|--------|-------------|
| -n, --limit <number> | Number of releases to show (default: 5) |
Example output:
⚡ Fetching deployment status...
╭────────────────────────────────────────────────╮
│ 📱 app-970384d3 → production │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ Current Release: v1.2.0 (iOS & Android) │
│ Status: ● active • 100% rollout │
│ Published: 2h ago │
╰────────────────────────────────────────────────╯
📦 Recent Releases (15 total)
Label Platform Status Rollout Published
────────────────────────────────────────────────────────
v1.2.0 all ● active 100% 2h ago
v1.1.0 all ○ expired 100% 3d ago
v1.0.0 ios ○ expired 100% 1w agogenerate-manifest
Fetch and display the manifest for a specific release.
upflux generate-manifest [options]| Option | Required | Description |
|--------|----------|-------------|
| -r, --release-id <id> | ✓ | Release ID (MongoDB ObjectId) |
| -o, --output <path> | | Save manifest to file |
Example:
# Print manifest to stdout
upflux generate-manifest --release-id 693507a19f6d6a79267633e8
# Save to file
upflux generate-manifest --release-id 693507a19f6d6a79267633e8 --output manifest.jsonScheduled Releases
Schedule releases to go live at a specific date and time. Perfect for coordinating updates with marketing campaigns, feature launches, or maintenance windows.
How It Works
- Create a release with the
--scheduleflag - The release is uploaded as a Draft
- Set the scheduled time in the Upflux Dashboard
- The release automatically goes live at the scheduled time
Creating a Scheduled Release
# Create a draft release for scheduling
upflux release --label v2.0.0 --schedule
# Output:
# ✓ Release uploaded successfully!
# ...
# Status: DRAFT
# 📅 Set schedule time in dashboardUse Cases
- Feature launches - Coordinate with marketing announcements
- Global releases - Release at optimal times for different regions
- Maintenance windows - Deploy during low-traffic periods
- Campaign coordination - Sync with promotional events
💡 Tip: Combine scheduled releases with rollout percentages for safer deployments. For example, schedule a 10% rollout first, then manually increase after monitoring.
Configuration
Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| UPFLUX_API_URL | API server URL | https://api.upflux.in/api |
Auth File
The CLI stores credentials in .upflux in the current directory:
{
"credentials": [
{
"key": "upflux_pub_xxx...",
"appId": "app-970384d3",
"deploymentId": "6933e683aa32fe18a1311bbb",
"deploymentName": "production"
},
{
"key": "upflux_pub_yyy...",
"appId": "app-970384d3",
"deploymentId": "6933e683aa32fe18a1311ccc",
"deploymentName": "staging"
}
],
"activeIndex": 0,
"lastReleaseHash": "a3f8c12d...",
"lastReleaseLabel": "v1.5.0"
}⚠️ Important: Never commit the
.upfluxfile to version control. It contains your publish keys. Add it to your.gitignore.
Publish Keys
Publish keys are used to authenticate the CLI and can be found in the Upflux dashboard under Settings → Keys.
Key format: upflux_pub_<prefix>_<secret>
Example: upflux_pub_prod_a1b2c3d4e5f6...
Development
# Install dependencies
pnpm install
# Build
pnpm run build
# Run locally
node dist/index.js --helpRequirements
- Node.js >= 18.0.0
- For React Native projects:
react-nativeCLI installed - For Capacitor projects: Built web assets in configured
webDir
License
MIT
