Expo

Zero-config fallback

If your project has an eas.json and no buildtree config (no buildtree.config.json and no buildtree field in package.json), the CLI uses a built-in default that runs:

# What the default does for ios:
eas build --local --platform ios --profile preview --output build/App.ipa

# And for android:
eas build --local --platform android --profile preview --output build/App.apk

The preview profile is assumed because it produces ad-hoc IPAs (the kind that work with the UDID-based device flow). If your eas.json doesn't define a preview profile, override the default with a buildtree config (below).

Then:

buildtree publish ios --env dev
buildtree publish android --env dev

Custom configuration

Override the defaults with a buildtree.config.json at your project root:

{
  "builds": {
    "ios": {
      "command": "eas build --local --platform ios --profile preview --output build/App.ipa",
      "artifact": "build/App.ipa"
    },
    "android": {
      "command": "eas build --local --platform android --profile preview --output build/App.apk",
      "artifact": "build/App.apk"
    }
  }
}

The artifact field is the exact file path the CLI checks for after the build command finishes. It must be a single path, not a glob. EAS chooses random output filenames by default, so pin the output explicitly with --output so the artifact path is predictable.

Upload builds by branch

The CLI accepts an environment and a branch. For pre-merge QA on a feature branch:

buildtree publish ios --env dev --branch feature/payments

For a release-ready checkpoint after merging to develop, omit --branch:

buildtree publish ios --env dev

See the pre-merge QA workflow for how the env + branch model fits a trunk-based dev cycle.

iOS provisioning

eas build --local uses EAS-managed credentials. For ad-hoc distribution, the provisioning profile must include every tester's UDID. See iOS distribution for the UDID collection flow.

After adding new UDIDs in Apple Developer, run eas credentials to regenerate the profile, then re-run your build.

Skip the build step

If your CI already builds the IPA / APK separately, skip publish and call upload directly with the artifact path:

buildtree upload ./build/App.ipa --env dev --branch feature/payments

This avoids the buildtree config requirement entirely; the file path is enough.

Parallel branch installs

Two builds that share a bundle identifier overwrite each other on the same test device. If your testers want side-by-side installs of feature/payments and feature/auth, use a variant bundle identifier per EAS profile:

{
  "build": {
    "preview": {
      "ios": {
        "bundleIdentifier": "com.yourcompany.app.preview"
      }
    }
  }
}

The variant bundle identifier needs its own ad-hoc provisioning profile registered with the same UDIDs.

Expo · Framework guide | buildtree docs