Migrate from Firebase App Distribution

Firebase App Distribution (FAD) ships builds to QA inside the Firebase ecosystem. It works, but the surface has not meaningfully evolved in years and a few rough edges have become routine pain:

  • Testers need to onboard through the Firebase App Tester app on Android, or accept an invitation tied to a Google account.
  • No branch or environment organisation. All builds for an app live in a single chronological list.
  • Tightly coupled to Firebase. If you do not otherwise use Firebase Analytics, Crashlytics, or Auth, you are pulling in a SDK and a Google Cloud project just for distribution.
  • Limited release-tagging story; "Release" in FAD is a build, not a version label you can pin a URL to.
  • The web dashboard does not surface QR codes; testers click through email or the Tester app.

buildtree replaces the distribution piece directly. Builds keep being built the way you build them; only the upload step changes. This guide assumes you have a FAD project with one or more apps and a CI pipeline that calls the FAD CLI, Fastlane plugin, or Gradle plugin.

What you keep, what you replace

FAD featurebuildtree equivalent
App (one per platform)Project (cross-platform; iOS + Android live in the same project)
Tester groupsAllowlist + Private mode (see Install access)
Public link via Firebase HostingPublic install URL on every build
firebase appdistribution:distributebuildtree upload
firebase_app_distribution Fastlane actionbuildtree upload
Gradle appDistributionUpload taskbuildtree upload
Release notesBuild metadata (auto-extracted from IPA/APK) + release tags
Group / tester managementAllowlist editor in the project dashboard
Build categories (none)Branch + environment + release tag
iOS UDID via Apple Dev portal manuallyBuilt-in UDID registration flow (see iOS distribution)

The 5-minute migration

  1. Install the CLI and authenticate:

    npm install -g @buildtree/cli
    buildtree login
    
  2. Replace your FAD upload step. In your CI workflow, swap the FAD invocation for:

    buildtree upload ./app.apk --env prod
    

    The first time you run this interactively the CLI prompts you to create a project and pick a slug; that slug becomes part of your install URLs and is reused on every subsequent upload. For preview builds tied to a feature branch:

    buildtree upload ./app.apk --env dev --branch feature/payments
    

    That is the only line that changes. Your build commands stay the same.

  3. Share the install URL with your QA team. The dashboard shows three URL types:

    • Pinned: a specific build, frozen forever.
    • Folder: always-latest for a given (env, branch) pair.
    • Release: frozen to a release tag.

    Most teams share the folder URL so testers always grab the freshest build without anyone copy-pasting a new link each release.

CI integration

Firebase CLI

If your CI runs firebase appdistribution:distribute today:

firebase appdistribution:distribute ./app.apk \
  --app 1:1234567890:android:abcdef \
  --groups internal-testers \
  --release-notes "Build $GITHUB_SHA"

Replace with:

buildtree upload ./app.apk --env prod

No app ID needed (the binary's bundle ID is read from the file). No --groups flag (testers are controlled by the project's allowlist on the dashboard, which doesn't change per build). Release notes map to a release tag with --release v1.5.0 if you want a frozen install URL per version.

Fastlane

Replace the firebase_app_distribution action with a shell call:

lane :distribute do
  sh "buildtree upload ../app.ipa --env prod"
end

Pass the API token via the BUILDTREE_TOKEN environment variable on the runner.

Gradle

Drop the com.google.firebase.appdistribution plugin and its config block. Add a single Gradle task or invoke the CLI directly in your CI step after assembleRelease:

./gradlew assembleRelease
buildtree upload ./app/build/outputs/apk/release/app-release.apk --env prod

GitHub Actions

Generate an API token from the dashboard's Settings → API Tokens page and add it as a GitHub repository secret called BUILDTREE_TOKEN. Then:

- name: Distribute to buildtree
  env:
    BUILDTREE_TOKEN: ${{ secrets.BUILDTREE_TOKEN }}
  run: |
    npm install -g @buildtree/cli
    buildtree upload ./build/app.apk --env prod

Full example workflows for iOS and Android: see GitHub Actions.

Tester onboarding

FAD requires testers to either install the Firebase App Tester app (Android) or accept an invitation tied to a Google account. buildtree replaces this with a one-line shareable URL:

  • Public projects: anyone with the URL can install. No tester signup, no Google account, no email gate.
  • Private projects (Solo and above): testers verify their email once via a magic link. They never sign up for an account or download anything. See Install access.

For most QA workflows this is the largest day-one win over FAD. External testers, contractors, and clients no longer need to be added to a Google project.

iOS UDID handling

FAD documents asking testers to register their UDID separately, then you paste it into the Apple Developer portal manually before re-uploading the build. buildtree builds the UDID flow into the platform:

  1. Share the project's public registration URL with iOS testers.
  2. They open it on the device they want to install on, fill in name and email.
  3. iOS prompts them to install a profile; the device's UDID lands in your dashboard.
  4. You approve each request from the Devices page.
  5. One click exports approved UDIDs in Apple Dev Portal format (the tab-separated UDID<TAB>Name format the bulk-add tool expects).
  6. Re-build your IPA with the new provisioning profile and upload.

The whole loop usually happens inside an hour for a tester you have never met. See iOS distribution for the full flow.

Release notes

FAD stores a freeform --release-notes string per build. buildtree extracts version, build number, bundle ID, and display name from the IPA or APK at upload time, so the "what changed" facts are surfaced without you typing them.

For human-readable changelogs, the closest equivalent is a release tag:

buildtree upload ./app.ipa --env prod --release v1.5.0

The release URL is frozen and shareable. Pair it with the changelog entry in your repo, in Slack, or in the PR description. A native release-notes field is on the roadmap.

What does not transfer automatically

  • Tester groups: there is no programmatic import of FAD tester rosters today. Export the email list from the FAD console and paste it into the buildtree allowlist as a multiline block (one email per line, or *@yourcompany.com for whole-team coverage).
  • Historical builds: FAD storage stays where it is until you delete the Firebase project. If you want to preserve specific release URLs on buildtree, re-upload the IPA or APK with buildtree upload --release <tag>.
  • Crashlytics / Analytics: these are separate Firebase products. They keep working with FAD removed; nothing in your app code changes. buildtree does not replace them.

Common questions

Do I need to change my build pipeline? No. buildtree replaces the upload step only. Local Xcode builds, Fastlane lanes, EAS local builds, native Gradle, and CI builds on any provider all produce a file, and buildtree upload takes it from there.

Can I keep Crashlytics? Yes. Crashlytics and FAD are unrelated products under the Firebase umbrella. Removing the FAD plugin or Fastlane action does not affect the Crashlytics SDK in your app.

Is the QA install link the same URL each release? Yes if you share the folder URL (/install/folder/<project>/<env> or /install/folder/<project>/<env>/<branch>). It always points to the latest build for that environment. Bookmark once, get fresh builds forever.

What does it cost compared to FAD? FAD is free as long as Google keeps the lights on (no SLA on continued availability). buildtree's Free tier covers 1 project, 5 GB, 30-day retention.

Need help

If you are migrating a larger team and want help mapping FAD tester groups to buildtree allowlists, email hello@buildtree.sh.

Migrate from Firebase App Distribution | buildtree docs