DevOps & Platform
12 min readAugust 12, 2026Updated August 19, 2026

arm64 vs x64: How to Check the Architecture of Any Machine, Binary or Container Image

AJ
Ajeet Yadav
Platform & Cloud Engineer
arm64 vs x64: How to Check the Architecture of Any Machine, Binary or Container Image

Quick answer

One command tells you whether a machine is arm64 or x64 — but the same question applies to binaries, container images and Kubernetes nodes, and each has its own answer. Here's the full toolkit: uname, file, docker manifest inspect, node labels, and how to decode every alias from aarch64 to AMD64.

12 min read · DevOps & Platform

On Linux and macOS, uname -m answers the question in one command — x86_64 means x64, aarch64 or arm64 means ARM. That covers the machine you are typing on. The trouble is that "is this arm64 or x64?" is really four different questions — about the machine, the OS, a binary, or a container image — and answering the wrong one is exactly how you end up staring at exec format error at 11pm.

This matters more now than it ever has. Your laptop is probably Apple Silicon (arm64), your CI runners are probably x64, and your cloud bill is quietly pushing you toward Graviton (arm64 again). Three environments, two architectures, and a build artifact that only works where it was compiled. Let's get the checks down cold.

Quick answer: check the machine

Linux

bash
uname -m

That's it. Decode the output:

OutputArchitectureAlso known as
x86_6464-bit Intel/AMDx64, amd64, AMD64
aarch6464-bit ARMarm64, ARM64
arm6464-bit ARM (macOS reports this)aarch64, ARM64
armv7l32-bit ARM (older Raspberry Pi)armhf
i686 / i38632-bit Intelx86

Want more detail — the exact CPU model, core count, whether it's a Graviton3 or an old Xeon:

bash
lscpu
# Architecture:        aarch64
# Model name:          Neoverse-V1     ← that's Graviton3

Or arch, which is an alias for uname -m on most systems. Or cat /proc/cpuinfo when you're inside a container so minimal it doesn't even ship uname.

macOS

Same command:

bash
uname -m
# arm64    → Apple Silicon (M1/M2/M3/M4)
# x86_64   → Intel Mac

But macOS has a trap the other platforms don't: Rosetta 2. An x64 process running under Rosetta on an Apple Silicon Mac sees x86_64 from uname -m — the translation layer is lying to it, by design. If your terminal (or the shell your CI agent spawned) is running translated, every architecture check downstream inherits the lie.

Check whether the current process is translated:

bash
sysctl -n sysctl.proc_translated
# 1  → running under Rosetta (x64 process on ARM hardware)
# 0  → running natively
# error "unknown oid" → Intel Mac, no Rosetta involved

And to see the real hardware regardless of what your process thinks:

bash
sysctl -n machdep.cpu.brand_string
# Apple M3 Pro

If you develop with Apple's native container runtime, this hardware question is settled for you — Apple's container tool requires Apple Silicon outright, and its local Kubernetes plugin inherits that constraint.

Windows

cmd
echo %PROCESSOR_ARCHITECTURE%
:: AMD64  → x64
:: ARM64  → ARM

In PowerShell:

powershell
$env:PROCESSOR_ARCHITECTURE
# or, unambiguous about OS vs process:
[System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture

Windows has the same emulation caveat as macOS: an x64 process emulated on a Windows-on-ARM machine sees AMD64 in PROCESSOR_ARCHITECTURE. Don't reach for PROCESSOR_ARCHITEW6432 here — that variable only exists inside 32-bit (WOW64) processes, and an emulated x64 process doesn't get it at all. Ask the OS instead: systeminfo | findstr /C:"System Type" reports the real machine (ARM64-based PC). The no-terminal answer: Settings → System → About → System type, which reads something like "ARM-based processor".

The naming mess, decoded once

Every vendor picked a different name for the same two architectures, and the aliases are the single biggest source of confusion in this topic. Pin this table to a wall:

These are all the same thingCanonical nameWho uses which
x64, x86_64, amd64, AMD6464-bit x86x86_64: uname, rpm · amd64: Docker, Go, Debian · AMD64: Windows · x64: Microsoft docs, Node.js
arm64, aarch64, ARM6464-bit ARM (ARMv8+)arm64: Docker, Go, macOS, Debian · aarch64: Linux uname, rpm · ARM64: Windows

Two rules of thumb: Docker and Go always say amd64/arm64, and Linux's uname always says x86_64/aarch64. When a download page offers both aarch64 and arm64 tarballs, they are almost certainly the identical architecture packaged by two different naming conventions — read the fine print, but don't panic.

(Historical footnote on why "amd64": AMD designed the 64-bit extension of x86, Intel adopted it later. The name stuck in Debian and Docker even though most amd64 machines run Intel chips.)

Check a binary's architecture

The machine being arm64 doesn't mean the binary you just downloaded is. file reads the executable header on any platform:

bash
file /usr/local/bin/terraform
# ELF 64-bit LSB executable, x86-64 ...          → x64 Linux binary
# ELF 64-bit LSB executable, ARM aarch64 ...     → arm64 Linux binary
# Mach-O 64-bit executable arm64                 → native Apple Silicon binary

macOS adds universal binaries — one file containing both architectures. file shows both slices, but lipo is the purpose-built tool:

bash
1lipo -archs /usr/bin/python3
2# x86_64 arm64e       ← universal: runs natively on both
3# (arm64e is Apple's hardened arm64 variant — system binaries use it;
4#  third-party universal binaries usually say plain arm64)
5
6lipo -archs ./some-old-tool
7# x86_64              ← will run on Apple Silicon, but only under Rosetta

This is worth checking on any Mac dev machine that's been migrated from Intel via Time Machine — it's common to find half your Homebrew toolchain still running x64 under Rosetta, silently slower, years after the hardware changed.

On Windows, dumpbin /headers app.exe | findstr machine (Visual Studio tools) or simply file from Git Bash does the same job for PE executables.

Check a container image's architecture

This is the check that actually saves incidents. A container image is built for an architecture, and pulling the wrong one is the canonical way to break a deployment.

An image you already have locally:

bash
docker inspect --format '{{.Os}}/{{.Architecture}}' nginx:latest
# linux/arm64

Careful with what this tells you: it reports the architecture of the variant you pulled, which Docker selected to match your machine. On your M-series Mac it says arm64; the same tag pulled on your CI runner would say amd64. It does not tell you what the tag offers.

What a tag offers, without pulling anything:

bash
docker manifest inspect nginx:latest | grep -A3 platform

For a multi-arch image you'll see a manifest list — one entry per platform (amd64, arm64, arm/v7, ...). For a single-arch image there's no list at all, just one manifest. That difference is the entire question of "will this image run on my Graviton nodes?".

The registry-native tools do it more cleanly and work in scripts:

bash
# crane (from go-containerregistry) — ideal for CI checks
crane manifest nginx:latest | jq '.manifests[].platform'

# skopeo — same idea, daemonless
skopeo inspect --raw docker://nginx:latest | jq '.manifests[].platform'

If you've moved off the Docker daemon entirely — see Docker vs Podman — podman manifest inspect and skopeo cover the same ground with no daemon in the loop.

Terraform Day-2 Operations Checklist

State hygiene, drift, imports, policy checks, and upgrade routines — everything after `terraform apply` works. Plain Markdown, commit it to your repo.

Free. Instant download. You'll also get the occasional deep-dive from the newsletter — unsubscribe anytime.

exec format error — what it means and why you got it

exec /app/server: exec format error

This error has exactly one meaning: the kernel was handed a binary for a different architecture. It is not a permissions problem, not a corrupt file, not a missing shared library — those all fail differently. The ELF header says aarch64, the CPU speaks x86_64 (or vice versa), and the kernel gives up at the first instruction.

The three ways it happens, in descending order of frequency:

  1. Built on an Apple Silicon laptop, deployed to x64. docker build with no --platform flag builds for the host — arm64 — and the image sails through push and pull before dying at container start on the x64 node.
  2. Single-arch base image on a mixed cluster. Your Dockerfile starts FROM some-internal-base:1.4, which was only ever built for amd64, and the pod lands on a Graviton node.
  3. A binary COPY'd into the image from the wrong release tarball. The image architecture is right; the vendored binary inside it isn't. This one is nasty because docker inspect reports the image as fine — only file on the binary inside reveals it.

In Kubernetes this surfaces as CrashLoopBackOff with the exec error in the logs, and it is one of the first things worth ruling out when a pod crashes instantly on some nodes and runs fine on others — the Kubernetes debugging guide covers the broader triage flow.

Why this got urgent: the three-way mismatch

For fifteen years everything was x64 and nobody ran these checks. Then three shifts landed at once:

  • Dev laptops went ARM. Apple Silicon made arm64 the default architecture of the machine your Dockerfile gets written on.
  • CI mostly stayed x64. GitHub Actions' standard ubuntu-latest runners are amd64 (ARM runners exist but are opt-in), so the artifact your pipeline builds usually doesn't match the laptop that authored it.
  • Cloud economics favour ARM. Graviton instances deliver roughly 20–40% better price-performance, which is why finance keeps asking about them — the Graviton migration guide covers that move end to end.

Laptop arm64, CI amd64, production either-or-both. Every artifact now crosses at least one architecture boundary, and the checks in this post are how you verify each crossing instead of discovering it at deploy time.

Building images that work on both

The fix for all of the above is publishing multi-arch images — one tag, a manifest list, and the runtime picks the right variant:

bash
# one-time builder setup
docker buildx create --use

# build and push both variants under one tag
docker buildx build --platform linux/amd64,linux/arm64 \
  -t registry.example.com/my-app:1.2.0 --push .

The catch is how the foreign architecture gets built. On an x64 runner, the arm64 half builds under QEMU emulation — correct output, but anywhere from 3× to 20× slower, and occasionally flaky for JIT-heavy builds (JVM, Node native modules). The grown-up setup is native runners for each architecture — an amd64 runner and an arm64 runner (Graviton, or GitHub's ARM runners) each building their own half, stitched together with docker buildx imagetools create. Slower to set up, dramatically faster per build. Multi-arch also multiplies image storage, which makes image size optimization pay off twice.

The Kubernetes angle

Every node advertises its architecture as a label:

bash
kubectl get nodes -L kubernetes.io/arch
# NAME       STATUS   ARCH
# node-1     Ready    amd64
# node-2     Ready    arm64

On a mixed-architecture cluster — typically x64 nodes plus a Graviton node group — any workload whose image is single-arch must be pinned with nodeAffinity (or a simple nodeSelector):

yaml
1affinity:
2  nodeAffinity:
3    requiredDuringSchedulingIgnoredDuringExecution:
4      nodeSelectorTerms:
5        - matchExpressions:
6            - key: kubernetes.io/arch
7              operator: In
8              values: ["amd64"]

The scheduler does not check image architecture — it will happily place an amd64-only pod on an arm64 node and let kubelet discover the problem as a crash. Mixed clusters are absolutely worth running for the Graviton savings, but the operating rule is: multi-arch images run unpinned, single-arch images run pinned, and nothing runs unverified. docker manifest inspect on every image in the workload is the pre-flight check.

Frequently Asked Questions

Are x64 and x86_64 the same thing?

Yes — and so are amd64 and AMD64. All four name the 64-bit x86 architecture. Likewise arm64, aarch64 and ARM64 all name 64-bit ARM. The vendor just determines the spelling: Docker says amd64/arm64, Linux's uname says x86_64/aarch64, Windows says AMD64/ARM64.

How do I check the architecture from inside a container?

uname -m works inside almost any Linux container — the answer comes straight from the kernel, and the tiny uname binary ships in busybox, alpine and every mainstream base image. On distroless or scratch images where you can't exec a shell at all, inspect the image from outside instead: docker inspect --format '{{.Architecture}}' <image>.

Can an arm64 machine run x64 containers?

Sometimes, slowly. Docker Desktop on Apple Silicon runs --platform linux/amd64 containers under QEMU/Rosetta emulation — fine for a quick test, wrong for benchmarks, and prone to breaking JIT-heavy runtimes. Native Linux hosts need binfmt/QEMU configured explicitly. Treat emulation as a convenience, never a deployment strategy.

Why does uname -m say x86_64 on my M-series Mac?

Your shell is running under Rosetta 2 — usually because the terminal app, or a parent process, is an x64 binary. Confirm with sysctl -n sysctl.proc_translated (returns 1 when translated) and check the real hardware with sysctl -n machdep.cpu.brand_string.

Is arm64 the same as ARMv8?

Effectively, yes. arm64/aarch64 is the 64-bit execution state introduced in ARMv8-A; everything you'll meet in cloud and on Apple Silicon (Graviton, Ampere, M-series) is ARMv8 or newer. 32-bit ARM (armv7l, armhf) is a different target and mostly survives on older Raspberry Pi hardware.

How do I know if a public image supports arm64?

docker manifest inspect <image> | grep architecture — no pull required. If the output lists both amd64 and arm64 platform entries, it's multi-arch. Docker Hub also shows supported architectures on each tag's page. Most official images have shipped arm64 for years; internal images are where the gaps live.

See also

Official References

Was this article helpful?

Be the first to rate this article

Related Topics

arm64
x64
CPU Architecture
Docker
Multi-arch
Kubernetes
Apple Silicon

Found this useful? Share it.

Practice this

Related tools

Read Next