CLI
sankofa release
Build and publish a base release — the signed store binary plus the OTA baseline that patches attach to. Full flag reference and examples for iOS and Android, Flutter and React Native.
sankofa release builds your app and publishes a base release: the signed store binary you submit to the App Store / Play Store, plus the OTA baseline that sankofa patch later ships code updates against. You run it once per app version.
sankofa release [platform] [options]platform is ios or android. Omit it and the CLI prompts. The stack (Flutter vs. React Native) is auto-detected from pubspec.yaml / package.json, and the CLI runs the matching pipeline.
What it produces
| Stack | iOS | Android |
|---|---|---|
| Flutter | Signed .ipa (App Store / TestFlight) + iOS OTA baseline | .aab (Play Store) or --apk + OTA baseline (libapp.so) |
| React Native | Signed .ipa + OTA archive + optional simulator preview | .aab/.apk + OTA archive + optional APK preview |
For Flutter, the store binary is built with the Sankofa Flutter engine and the OTA wiring baked in. This is why you must publish through sankofa release rather than a raw flutter build — only the CLI registers the server-side baseline, and only the Sankofa-engine binary can accept patches later.
Common options
These apply to both Flutter and React Native.
--publishflag--env <environment>live | test--rollout <percent>0–100default 100--mandatoryflag--description <desc>string--project <path>path--dry-runflagFlutter releases
Android
# Play Store bundle (default)
sankofa release android
# Sideload-installable APK instead of an AAB
sankofa release android --apk
# Non-interactive with a staged rollout + note
sankofa release android --publish --rollout 25 --description "1.4.0 GA"
# Build + verify locally, upload nothing
sankofa release android --dry-runsankofa release android builds the AAB (or APK), extracts the AOT baseline (libapp.so), verifies the embedded engine is a genuine Sankofa build, captures the auto-diff base for future patches, and registers the baseline on the server. The AAB it prints is your deployable — upload that to the Play Console, not the output of a raw flutter build.
iOS
# Signed .ipa for App Store Connect / TestFlight
sankofa release ios
# Build the .xcarchive only (sign + export later in Xcode)
sankofa release ios --no-codesign
# Non-interactive
sankofa release ios --publish --rollout 50 --description "1.4.0"sankofa release ios builds a signed .ipa (your store artifact — Sankofa never stores it), captures the auto-diff base, and registers an iOS OTA baseline on the server. iOS OTA runs through the engine's bytecode interpreter, so the baseline is a small signed envelope that the real code (shipped later by sankofa patch ios) attaches to.
Flavored apps
Apps with Gradle product flavors and a per-flavor entry point need both --flavor and --target, or the build picks the wrong main().
sankofa release android --flavor staging -t lib/main_staging.dart
sankofa release android --flavor production -t lib/main_production.dart
sankofa release ios --flavor staging -t lib/main_staging.dartIf you have no lib/main.dart and pass neither flag, the CLI stops with a hint showing the exact command to use.
Flutter-specific options
--apkflag--appbundleflagdefault on--flavor <name>string-t, --target <file>path--no-codesignflag--preview-artifactflag--dart-define <KEY=VALUE>repeatableReact Native releases
React Native uses the same command surface. release bundles the JavaScript + assets, builds a native preview artifact, and (unless you opt out) the signed store binary.
sankofa release ios
sankofa release android --publish --rollout 50 --description "v1.2.0"
# OTA archive only, skip the multi-minute signed-binary build
sankofa release android --skip-distribution
# Choose the Android format
sankofa release android --apk
sankofa release android --appbundleReact Native-specific options
--entry-file <file>path--output-dir <dir>pathdefault ./build--no-native-artifactflag--skip-distributionflag--ios-export-method <method>stringdefault app-store--ios-team-id <id>string--ios-export-options <path>path--apk / --appbundleflagdefault appbundleAfter a successful release
The command prints the release label, platform, target version, rollout %, release ID, and the on-disk path + SHA-256 of every artifact it produced. Two follow-ups are the norm:
Submit the store binary
Upload the printed
.ipato App Store Connect (Transporter, Xcode Organizer, orxcrun altool) or the.aabto the Play Console. Sankofa does not submit it for you.Ship code updates with patch
Once the base release is live, every subsequent code change ships over-the-air with
sankofa patch— no new store submission.
Related commands
sankofa patch— ship a code-only update against this release.sankofa dist <ios|android>— build only the signed store binary, no OTA.sankofa submit <ios|android>— upload a signed binary to App Store Connect / Play Console.sankofa status— list all releases and patches for the current project.sankofa preview— run a build for QA before you submit.