Native ARM64: the default now, not the exception
Every Apple Silicon Mac's CPU is ARM64. A macOS app compiled for arm64 runs directly on it, no translation involved — and so does a Linux guest running an arm64 kernel and userland, which is what Virtualization.framework actually boots, covered in the VM fundamentals post. This is the fast, unremarkable path: native code talking to native silicon. Everything below this section is about what happens when the software you need wasn't built for that.
Rosetta 2 for macOS apps — and why it's a different thing from Rosetta for Linux
This is worth being precise about, because the name is reused for two mechanically different things. Rosetta 2 for macOS apps is the host-level translation layer that lets an x86_64-only Mac app launch and run on Apple Silicon at all, transparently, the moment you double-click it — no setup, no opt-in. Rosetta for Linux, covered in depth in the Ubuntu on Apple Silicon post, is a separate, guest-side mechanism: Velo Workspaces wires it into a Linux VM as a VirtioFS share plus a one-time binfmt registration, and it only translates binaries you explicitly ask it to, inside the guest. Same brand name, same underlying Apple technology, genuinely different integration point and different limits — don't assume a fact about one applies to the other.
Universal binaries are the third piece of this picture, and the reason well-maintained macOS apps don't need Rosetta at all: a single app bundle can ship both an arm64 slice and an x86_64 slice, built with Apple's lipo tooling, and the OS picks the right one automatically at launch. An app that's still x86_64-only simply hasn't shipped that second slice yet — it's a build configuration gap, not a platform limitation.
Package managers: two install prefixes, on purpose
Homebrew makes this split visible in the filesystem itself: on Apple Silicon it installs to /opt/homebrew, while an Intel Mac (or a Rosetta-mode Homebrew install, launched via arch -x86_64) uses /usr/local. That's a deliberate choice, not an accident — Apple recommends third-party software use /opt on Apple Silicon rather than the historically Intel-associated /usr/local, and keeping two separate prefixes lets both hierarchies coexist without one silently shadowing the other. The same underlying problem shows up a level down inside a Linux guest, where a distro's arm64 ports repository doesn't always mirror every package available for amd64 — the exact gap covered concretely in the Ubuntu post's Rosetta section.
Containers: an image is really several images wearing one name
A modern multi-arch container image isn't one image — it's a manifest list pointing at separate arm64 and amd64 builds, with the registry serving whichever one matches the pulling machine automatically. That's what makes docker pull "just work" identically on an Apple Silicon Mac and an x86 CI server for a well-maintained image. Ask for the architecture your machine doesn't have — docker pull --platform linux/amd64 on Apple Silicon — and Docker Desktop doesn't magically run x86 code natively; it falls back to QEMU's software emulation under the hood, the same TCG mechanism covered in the Virtualization.framework vs. QEMU post. It works, but it's genuinely emulated, not accelerated, and it's noticeably slower for anything CPU-heavy.
CI/CD: check what your runner actually is
This one has shifted recently enough to be worth stating plainly: GitHub Actions' macos-26 label — the current default macOS runner — runs natively on Apple Silicon (arm64), with a separate macos-26-intel label for x64, and Intel-based macOS runners are being phased out entirely by August 2027. If your build matrix still assumes "the macOS runner" means x86_64, it's testing an architecture fewer and fewer of your actual users are running. Explicitly matching CI runner architecture to what ships is a small check worth adding, not an edge case.
The practical version
Architecture mismatch bites in a small number of predictable places: a dependency that only ships x86_64 binaries, a container image built without a multi-arch manifest, a CI runner testing the wrong architecture, or a Linux guest missing an arm64 package your distro's ports repo never built. None of these are Apple Silicon being unusually difficult — they're the ordinary cost of a platform transition that's now several years in, mostly finished, with a shrinking set of specific gaps rather than a blanket compatibility problem.
Related reading: what a VM on Apple Silicon actually is, Rosetta for Linux in depth, Virtualization.framework vs. QEMU, and why Arch Linux has no official arm64 build at all. Or download Velo Workspaces and try it yourself.