Keep your pipeline. Change the runner.

Run these workflows on a cloud Mac

Move the build and test steps that require macOS to a dedicated physical Mac mini. Native iOS, Flutter, Unity and MLX workloads each have different resource demands. Start with the commands and prerequisites, then choose a plan based on memory, caching and concurrency needs. These are practical workflows—not benchmark results.

A dedicated physical machine, not a VM. Rent by the day from $20.5/day. Check the portal for real-time availability.

Browse by workload

5 workflows, all shown. Choose a category to highlight and jump to matching workflows; the others will remain visible.

From trigger to deliverable

Find the right build step.

Run these commands on the node. Install your project dependencies first, then set the required environment variables. Paths should point to your own project and configuration files. Copying a command does not run it.

Native iOS · Nightly build

Trigger an archive on Git push; let fastlane handle the upload.

Register the cloud Mac as a GitHub Actions self-hosted runner, GitLab Runner or Jenkins agent. On a push to your release branch, check out the pinned commit, then create a Release archive and IPA. Uploading to TestFlight is a separate step, so build and upload failures can be retried independently.

Set up these three things

  • Set WORKSPACE, SCHEME and EXPORT_OPTIONS to your workspace, shared scheme and export configuration.
  • Configure the signing certificate and provisioning profile for the build user. You can manage them with fastlane match and inject decrypted credentials through your CI secrets.
  • Set ASC_API_KEY_JSON to the App Store Connect API key JSON used by fastlane. Keep the key out of your source repository.

What to verify

Archive build/App.xcarchive, the exported IPA, the commit identifier and the Xcode version. Confirm that TestFlight received the expected build; a successful build command does not mean the upload is complete.

Why this plan: Host M4 Plus, with 24GB of unified memory, suits everyday builds with multiple targets. Start with serial builds, then consider concurrency based on memory pressure and DerivedData usage.

archive → export → upload
set -euo pipefail
: "${WORKSPACE:?Set WORKSPACE}"
: "${SCHEME:?Set SCHEME}"
: "${EXPORT_OPTIONS:?Set EXPORT_OPTIONS}"
: "${ASC_API_KEY_JSON:?Set ASC_API_KEY_JSON}"

mkdir -p build
xcodebuild -version
xcodebuild \
  -workspace "$WORKSPACE" -scheme "$SCHEME" \
  -configuration Release \
  -destination 'generic/platform=iOS' \
  -archivePath build/App.xcarchive archive

xcodebuild -exportArchive \
  -archivePath build/App.xcarchive \
  -exportPath build/export \
  -exportOptionsPlist "$EXPORT_OPTIONS"

IPA_PATH="$(find build/export -type f -name '*.ipa' -print -quit)"
test -n "$IPA_PATH"
bundle exec fastlane pilot upload \
  --ipa "$IPA_PATH" \
  --api_key_path "$ASC_API_KEY_JSON"
Plan: Host M4 Plus · M4 / 24GB / 512GB Suggested node: Tokyo, Japan
Rent Host M4 Plus

Cross-platform · Flutter

Keep Android on Linux. Move only the iOS job.

You don't need to move the entire cross-platform pipeline. Keep Android jobs on your Linux runner and use the cloud Mac for CocoaPods, Xcode builds and IPA exports. Use the same commit identifier on both platforms and collect the artifacts at the end. If one job fails, rerun just that job.

Make cache invalidation explicit

  • Pin Flutter, Ruby, CocoaPods and Xcode versions. Keep pubspec.lock, Podfile.lock and Gemfile.lock.
  • Cache Pub and CocoaPods downloads. Cache keys should include at least the toolchain versions and dependency lockfile hashes.
  • Don't let concurrent jobs write to the same project directory. Isolate DerivedData and output directories by job to avoid cache conflicts.

What to verify

Save the signed IPA from build/ios/ipa, the build logs and the dependency lockfiles. Install the artifact on a device or validate it in a downstream test job before marking the build as ready to release.

Why this plan: Host M4 Lite is a good starting point for a single job. If you also launch simulators, run tests and build packages, measure peak memory first; then consider Host M4 Plus rather than adding concurrency straight away.

Flutter · iOS job
set -euo pipefail
: "${EXPORT_OPTIONS:?Set EXPORT_OPTIONS}"

flutter --version
xcodebuild -version
flutter doctor -v
bundle check || bundle install
flutter pub get

(
  cd ios
  bundle exec pod install --deployment
)

flutter build ipa \
  --release \
  --export-options-plist="$EXPORT_OPTIONS"

find build/ios/ipa -type f -name '*.ipa' -print
Plan: Host M4 Lite · M4 / 16GB / 256GB Suggested node: Singapore
Rent Host M4 Lite

Games · iOS builds

Build on Unity's exported project, then sign, package and check the size.

Unity asset processing and Xcode compilation are separate stages. First, use your project's export workflow to generate the Xcode project. Then run the archive and export steps on the cloud Mac. Compare package sizes with the same asset settings to identify whether a change came from assets, build options or the export process.

Define the export boundary

  • UNITY_IOS_DIR should point to the exported iOS project directory. The commands below start at the Xcode stage and don't replace your Unity build scripts.
  • If a plugin generated a workspace, set UNITY_WORKSPACE; otherwise, use Unity-iPhone.xcodeproj. Don't mix the two approaches.
  • Set up signing and EXPORT_OPTIONS. To generate an App Thinning report, enable the corresponding report option in the export configuration.

What to verify

Check the IPA file size, export logs and asset changes. The compressed IPA size isn't the same as the size users download or install. Use the export report and distribution processing results when deciding whether to release.

Why this plan: Host M4 Pro has 64GB of unified memory and a 2TB SSD, making it a good fit for large asset projects and archive caches. Measure resource use during asset import, compilation and export before planning your job queue.

Unity export → Xcode
set -euo pipefail
: "${UNITY_IOS_DIR:?Set UNITY_IOS_DIR}"
: "${EXPORT_OPTIONS:?Set EXPORT_OPTIONS}"

mkdir -p build
if [ -n "${UNITY_WORKSPACE:-}" ]; then
  xcodebuild -workspace "$UNITY_WORKSPACE" \
    -scheme Unity-iPhone -configuration Release \
    -destination 'generic/platform=iOS' \
    -archivePath build/Game.xcarchive archive
else
  xcodebuild \
    -project "$UNITY_IOS_DIR/Unity-iPhone.xcodeproj" \
    -scheme Unity-iPhone -configuration Release \
    -destination 'generic/platform=iOS' \
    -archivePath build/Game.xcarchive archive
fi

xcodebuild -exportArchive \
  -archivePath build/Game.xcarchive \
  -exportPath build/game-export \
  -exportOptionsPlist "$EXPORT_OPTIONS"

find build/game-export -type f -name '*.ipa' \
  -exec du -h {} \;
Plan: Host M4 Pro · M4 Pro / 64GB / 2TB Suggested node: Seoul, South Korea
Rent Host M4 Pro

Native iOS · Compatibility testing

Pin Xcode, then run your simulator matrix one device at a time.

Testing compatibility with a new OS isn't just about a successful build. Add core navigation, permission prompts, dark mode and key layouts to your tests, and save results by Xcode version and simulator runtime. Make the matrix reproducible with serial runs first, then decide which tests are worth parallelising.

Track both versions and devices

  • Use xcodes to manage multiple Xcode versions. Set DEVELOPER_DIR for each job to select a version without changing the machine-wide default toolchain while other jobs are running.
  • List the simulators available in your Xcode version, then set SIM_A and SIM_B to the UDIDs of different devices. Install the required runtimes in advance.
  • Keep the .xcresult bundle, not just the last line of terminal output. UI screenshots, failed tests and retry records should all map to the same commit.

What to verify

Check the test exit code and result bundle for each target. Simulator tests don't replace validation on physical devices for peripherals, performance or distribution; schedule those separately.

Why this plan: Host M4 Plus is a solid starting point for routine regression tests. The number of simulators you can run depends on actual memory pressure; 24GB doesn't mean unlimited concurrency.

Xcode · simulator matrix
set -euo pipefail
: "${DEVELOPER_DIR:?Set DEVELOPER_DIR}"
: "${WORKSPACE:?Set WORKSPACE}"
: "${SCHEME:?Set SCHEME}"
: "${SIM_A:?Set SIM_A}"
: "${SIM_B:?Set SIM_B}"
export DEVELOPER_DIR

mkdir -p build
xcodebuild -version
xcrun simctl list devices available

RUN_ID="$(date +%s)-$$"
for DEVICE_ID in "$SIM_A" "$SIM_B"; do
  xcodebuild test \
    -workspace "$WORKSPACE" \
    -scheme "$SCHEME" \
    -destination "platform=iOS Simulator,id=$DEVICE_ID" \
    -parallel-testing-enabled NO \
    -resultBundlePath \
      "build/$RUN_ID-$DEVICE_ID.xcresult"
done
Plan: Host M4 Plus · M4 / 24GB / 512GB Suggested node: Hong Kong
Rent Host M4 Plus

AI · MLX inference

Load the model into unified memory and test for stable performance.

Use MLX to load a compatible model on an Apple Silicon physical node, then record generation speed, peak memory use and context length. Start with a single request before testing batches. Build jobs and inference experiments share the same machine, so don't run both at full load without measuring first.

Check the model and resource requirements

  • MODEL_DIR should point to a prepared directory containing an MLX-compatible model. Check the model's source, licence, quantisation format and dependency versions.
  • 64GB is the machine's total unified memory, shared by the system, model weights, caches and other processes. Whether the model fits depends on its configuration and context length.
  • Keep prompts and generation lengths consistent, and record cold starts separately from subsequent requests. Don't include model download time in inference throughput.

What to verify

Keep the model version, quantisation settings, MLX environment and run logs. Use /usr/bin/time -l to help monitor process usage, then check system memory pressure to see whether swapping occurs.

Why this plan: Host M4 Pro's 64GB of unified memory suits experiments that need more memory. The 2TB SSD is for model files and experiment artifacts; it doesn't increase the memory available to the model.

MLX · local inference
set -euo pipefail
: "${MODEL_DIR:?Set MODEL_DIR}"

python3 -m venv .venv
. .venv/bin/activate
python -m pip install mlx-lm
mkdir -p build

python -m pip freeze > build/mlx-environment.txt
/usr/bin/time -l \
  python -m mlx_lm.generate \
    --model "$MODEL_DIR" \
    --prompt "Explain reproducible builds." \
    --max-tokens 128 \
    > build/mlx-output.txt \
    2> build/mlx-metrics.txt

cat build/mlx-output.txt
cat build/mlx-metrics.txt
Plan: Host M4 Pro · M4 Pro / 64GB / 2TB Suggested node: US West
Rent Host M4 Pro

After copying a command, check its variables and signing configuration against your project before running it.

A recommendation, not a performance guarantee

Size your plan with a full run.

Node recommendations are based on team collaboration time zones, not measured network latency. Your repository, artifact storage and team location also affect the experience.

01

Measure peak resource use

Run a complete job with a fixed commit and dependency versions. Record memory pressure, cache size and artifact size separately; don't choose a plan based on a single build-time figure.

02

Separate queue time from run time

Start with a single executor. Once the job itself is stable, increase concurrency. Track runner wait time, dependency download time and build time separately.

03

Choose a node near your workflow

Choose from 5 locations: Singapore, Tokyo, Seoul, Hong Kong and US West. Check project sync and interactive access first, then set a consistent location for your team.

Define what success looks like

What do you want to see tomorrow morning?

These are example goals for three roles, not customer testimonials or benchmark results. Defining acceptance criteria in your pipeline is more useful than optimising for a single faster build.

“I want the archive, test results and failure logs for the right commit in the morning—not another trip to check the build machine at the office.”
iOS lead · nightly build goal
“I only want to move the Flutter iOS job. Both platforms should use the same commit, and I should be able to rerun a failed job without restarting the whole pipeline.”
Mobile architect · pipeline split goal
“I need to keep the model version, memory use and generated output together. Reproducible experiments give me a sound basis for choosing hardware next time.”
ML engineer · inference experiment goal

Choose the workload, then choose the machine.

Start with Host M4 Lite for single jobs, choose Host M4 Plus for multiple targets and routine regression tests, or use Host M4 Pro for large projects and memory-intensive experiments. Compare the 3 plans, 4 rental periods and add-ons on the plans page, then place your order.

All prices are in USD. Payment is available via USDT-TRC20 and Visa / Mastercard / Amex (through Stripe). Available payment gateways are confirmed by the backend.