> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Devin macOS support

> Run Devin on macOS VMs with Xcode and the iOS Simulator to build, run, and test Apple-platform apps.

Devin now has access to macOS virtual machines. This means Devin can now build and test iOS and macOS applications.

<Note>
  If you're on a Dedicated SaaS deployment, please reach out to your account team to enable macOS VMs.
</Note>

## How it works

macOS support is built on the same [declarative configuration](/onboard-devin/environment/blueprints) system as Linux. The `runs-on` field in your blueprint tells Devin which platform to build and run on, and each platform gets its own snapshot.

The main differences from Linux are the shell, the file system layout, and the package manager:

| Aspect           | Linux (default)        | macOS                                |
| ---------------- | ---------------------- | ------------------------------------ |
| Home directory   | `/home/ubuntu`         | `/Users/devin`                       |
| Repo directory   | `~/repos/<repo-name>`  | `/Users/devin/repos/<repo-name>`     |
| Shell            | `bash`                 | `zsh`                                |
| Package manager  | `apt-get`              | `brew` (Homebrew at `/opt/homebrew`) |
| File attachments | `/home/ubuntu/.files/` | `/Users/devin/.files/`               |

## Starting a macOS session

You can choose macOS per session:

* **Blueprint**: add `runs-on: macos` so the repo's snapshot is built for macOS (see below).
* **Slack**: use the `!mac` [bang command](/integrations/slack) to start a session on a macOS VM.
* **API**: set `platform: "macos"` when creating a session, schedule, or automation. See the [API reference](/api-reference/overview).

## Writing macOS blueprints

### Single-platform blueprint

If your repository only targets Apple platforms, use `runs-on: macos` at the top level:

```yaml theme={null}
runs-on: macos

initialize:
  - name: "Install build tooling"
    run: |
      brew install xcodegen swiftlint xcbeautify

maintenance: |
  xcodebuild -resolvePackageDependencies -project MyApp.xcodeproj -scheme MyApp

knowledge:
  - name: build
    contents: xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 17' build
  - name: test
    contents: xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 17' test
  - name: lint
    contents: swiftlint
```

### Multi-platform blueprint

To build the same repository for more than one platform, write each platform as a separate YAML document separated by `---`. Each document declares its own `runs-on` label. See the [Multi-document YAML](/onboard-devin/environment/blueprints#blueprint-sections) callout in the blueprint guide for background on this format.

```yaml theme={null}
runs-on: default
initialize: |
  apt-get update && apt-get install -y build-essential

maintenance: |
  npm install

knowledge:
  - name: test
    contents: npm test

---
runs-on: macos
initialize: |
  brew install cocoapods

maintenance: |
  npm install
  (cd ios && pod install)

knowledge:
  - name: test
    contents: npm test
```

Each document produces a separate snapshot build for its platform. Sessions boot from the platform-specific snapshot.

<Warning>
  The top-level YAML must be a mapping, not a sequence. Writing the example above as a single list (`- runs-on: default` / `- runs-on: macos`) is rejected by the backend. Use the `---` separator shown above.
</Warning>

## The `runs-on` field

The `runs-on` field maps to a registered machine config on your account:

| Value                | Platform                 |
| -------------------- | ------------------------ |
| `default` or `linux` | Linux (default platform) |
| `macos`              | macOS                    |
| `windows`            | Windows                  |

You can specify `runs-on` as a string or a list:

```yaml theme={null}
# Single platform
runs-on: macos

# Multiple platforms in one block (same commands run on each)
runs-on: [default, macos]
```

<Warning>
  The list syntax runs identical commands on every platform in the list. Only use it when commands are truly cross-platform (e.g. `npm install`). For platform-specific commands (like `apt-get` on Linux or `brew` on macOS), use the [multi-document format](#multi-platform-blueprint) instead.
</Warning>

## Usage and cost

macOS sessions consume the same usage as equivalent Linux or Windows sessions. There is no macOS surcharge. For details on how usage is metered, see [Usage](/admin/billing/usage#macos-sessions).

## What's preinstalled

macOS session images ship with the Apple toolchain already installed, so your blueprint doesn't have to download it:

| Category        | Included                                                                                                                                                    |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Xcode           | The latest Xcode 26 release as the default at `/Applications/Xcode.app`, plus the Xcode 27 prerelease alongside it (e.g. `/Applications/Xcode-27.0-RC.app`) |
| Simulators      | One iOS Simulator runtime per installed Xcode (iOS 26 and iOS 27), each with a preconfigured iPhone device                                                  |
| Apple tooling   | `xcodebuild`, `xcrun`, `simctl`, Swift, and the Metal toolchain                                                                                             |
| Package manager | Homebrew at `/opt/homebrew`                                                                                                                                 |
| Languages       | Node.js, Python, Java, Rust (plus `npm`, `yarn`, `pnpm`)                                                                                                    |
| CLI tools       | `git`, `git-lfs`, `gh`, `jq`, `ripgrep`, `ffmpeg`, `wget`, `direnv`                                                                                         |
| Browser         | Google Chrome                                                                                                                                               |

Versions move as Apple ships new releases and the image is refreshed. To see exactly what a session has, ask Devin to run:

```bash theme={null}
sw_vers
xcodebuild -version
ls -d /Applications/Xcode*.app
xcrun simctl list runtimes
```

### Selecting an Xcode version

The default Xcode is the one `xcode-select` points at. To use another installed version for a single command, set `DEVELOPER_DIR`:

```bash theme={null}
DEVELOPER_DIR=/Applications/Xcode-27.0-RC.app/Contents/Developer /usr/bin/xcodebuild -version
```

Use `/usr/bin/xcodebuild` (the shim that honors `DEVELOPER_DIR`) rather than a `xcodebuild` resolved from a specific Xcode's `Contents/Developer/usr/bin` on `PATH`, which reports its own version regardless of `DEVELOPER_DIR`.

Or switch the default for the whole session:

```bash theme={null}
sudo xcode-select -s /Applications/Xcode-27.0-RC.app
```

Put whichever you need in your blueprint so every session starts on the right toolchain.

## macOS session behavior

### Shell

macOS sessions use **zsh** as the default shell. Most POSIX shell commands work unchanged from Linux blueprints, but note the BSD userland: `sed -i` requires an argument (`sed -i ''`), and GNU tools like `gsed`, `gdate`, and `greadlink` come from the Homebrew `coreutils` formula.

### Paths

```yaml theme={null}
# Linux paths
- run: cp config.json ~/.config/myapp/config.json

# macOS paths
- run: cp config.json /Users/devin/.config/myapp/config.json
```

Repositories are cloned to `/Users/devin/repos/<repo-name>`, and files you upload to a session are written to `/Users/devin/.files/`.

### Secrets

[Secrets](/product-guides/secrets) are available as environment variables during sessions (`$SECRET_NAME`), same as on Linux. This is how to supply App Store Connect API keys, signing credentials, or private registry tokens:

```yaml theme={null}
maintenance:
  - name: "Configure private Swift package registry"
    run: |
      git config --global url."https://$GIT_TOKEN@github.com/".insteadOf "https://github.com/"
```

### Session sleep and wake

Sessions snapshot to disk when they sleep. Everything on disk survives a wake: installed tools, cloned repos, build caches, derived data. Running processes do not: dev servers, simulators, and watchers need to be restarted after the session wakes up.

### Computer Use

[Computer Use](/work-with-devin/computer-use) works on macOS sessions: Devin gets a full macOS desktop with Chrome, mouse, and keyboard, and can test macOS-native apps as well as web apps, and [record](/work-with-devin/testing-and-recordings) what it does. Devin uses the Command key for macOS shortcuts (⌘C, ⌘V, ⌘Tab) rather than Control.

### iOS Simulator

Devin can boot and drive the iOS Simulator directly:

```bash theme={null}
open -a Simulator                  # boot the default device
xcrun simctl list devices          # see available devices
xcrun simctl boot "iPhone 17"      # boot a specific device
xcrun simctl install booted MyApp.app
xcrun simctl launch booted com.example.MyApp
```

The **iOS Simulator** tab in the session workspace streams the booted simulator, so you can watch Devin tap through your app in real time. It's the Apple equivalent of [Android emulator support](/onboard-devin/environment/android-emulation).

## Tips & Tricks

### Warm build caches

A cold Xcode build results in a suboptimal developer experience, with longer build time. Use the `maintenance` field in `environment.yml` to prewarm the cache.

```yaml theme={null}
runs-on: macos

initialize:
  - name: "Install tooling"
    run: brew install cocoapods xcodegen swiftlint

maintenance:
  - name: "Resolve dependencies and warm the build"
    run: |
      xcodebuild -resolvePackageDependencies -project MyApp.xcodeproj -scheme MyApp
      xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 17' build-for-testing
  - name: "Pre-boot the simulator"
    run: xcrun simctl boot "iPhone 17" || true
```

Resolved Swift packages, CocoaPods, and DerivedData will persist in the snapshot, so new sessions start from an incremental build.

### Network access

Builds that fetch from CocoaPods, Swift Package Manager, Firebase, or a private registry need those hosts reachable. If your organization runs with a restricted network policy, make sure the macOS allowlist covers the same registries your Linux builds use. The two are configured separately, and a missing entry usually shows up as a dependency-resolution or TLS failure in the middle of a build.

### Running containers

macOS VMs have no nested hardware virtualization, so a container runtime has to fall back to QEMU's software emulation (TCG). Colima detects this and switches to emulation on its own:

```bash theme={null}
brew install colima docker qemu lima
colima start --vm-type qemu --arch aarch64 --cpu 4 --memory 8 --disk 30
```

The VM takes two to four minutes to become usable, and the first start can time out waiting for SSH while the emulated guest brings up networking, so retry the `colima start` if it fails. Containers then run roughly 15 to 25x slower on CPU than native, with a few seconds of startup each; pulls run at host network speed. That's fine for a linting or packaging container, painful for compiling. For container-heavy work, use a Linux session or point the macOS session at a remote Docker daemon.

### Don't install Xcode in a blueprint unless you have to

Xcode is a multi-gigabyte download, and Apple gates it behind an Apple ID. Prefer the versions already in the image, selected with `DEVELOPER_DIR` or `xcode-select`. If you need a different release or beta, you can store an Apple ID as a [secret](/product-guides/secrets) and have the blueprint download that version, at the cost of a much slower build.

## Limitations

| Limitation              | Detail                                                                                                                        |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Docker and containers   | No nested hardware virtualization, so containers run under software emulation. See [Running containers](#running-containers). |
| Physical devices        | No USB passthrough, so builds and tests run on simulators, not physical iPhones or iPads.                                     |
| Xcode downloads         | Fetching another Xcode or simulator runtime requires supplying Apple ID credentials and a long download.                      |
| Performance measurement | Instruments-style timing and profiling inside a VM isn't representative of real device performance.                           |

## Troubleshooting

**Builds are much slower in the first session after a snapshot rebuild.** DerivedData was rebuilt from scratch. Add a `build-for-testing` step to `maintenance` so the snapshot carries a warm build.

**`xcodebuild` picks the wrong toolchain.** Check `xcode-select -p`, and set `DEVELOPER_DIR` explicitly in the blueprint step.

**A destination isn't found.** Run `xcrun simctl list devices available` to see what the installed runtimes actually provide, and match the `-destination` name and OS to it.

**Dependency resolution hangs or fails with a TLS error.** The host is likely missing from your organization's network allowlist for macOS. See [Network access](#network-access).
