
I Tried Out Lambda MicroVMs on the x86 Architecture
This page has been translated by machine translation. View original
Introduction
On November 11, 2026, x86 architecture support for Lambda MicroVMs was announced.
At GA in June 2026, the only supported architecture was Arm (AWS Graviton). With this update, you can now choose between Arm and x86.
This article introduces the results of trying x86 Lambda MicroVMs in the Tokyo region.
Specifying x86
Querying supported versions
x86 is supported in managed base image version 3 and later. You can check supportedCpuConfigurations for each version with list-managed-microvm-image-versions.
aws lambda-microvms list-managed-microvm-image-versions --image-identifier arn:aws:lambda:ap-northeast-1:aws:microvm-image:al2023-1 --region ap-northeast-1
| Version | Created (JST) | supportedCpuConfigurations |
|---|---|---|
| 3 | 2026-10-24 | ARM_64, X86_64 |
| 2 | 2026-09-30 | ARM_64 |
| 1 | 2026-07-17 | ARM_64 |
| 0 | 2026-06-18 | ARM_64 |
Creating and launching an image
I used a Dockerfile based on the multi-architecture node:24-alpine.
FROM node:24-alpine
WORKDIR /app
COPY app.js .
EXPOSE 8080
CMD ["node", "app.js"]
I added --cpu-configurations architecture=X86_64 to create-microvm-image to create an x86 image. The AWS CLI version is 2.40.2.
aws lambda-microvms create-microvm-image --name devio-x86-test-x86 --code-artifact uri=s3://amzn-s3-demo-bucket/app.zip --base-image-arn arn:aws:lambda:ap-northeast-1:aws:microvm-image:al2023-1 --build-role-arn arn:aws:iam::123456789012:role/MicroVMBuildRole --cpu-configurations architecture=X86_64
The cpuConfigurations in the response was X86_64. Because I did not specify the base image version, baseImageVersion became 3.1.
"cpuConfigurations": [
{
"architecture": "X86_64"
}
],
This is the result of calling /arch on the MicroVM launched from this image. EX and TOKEN_x86 are the MicroVM's endpoint and authentication token.
$ curl -sS -m 30 "https://$EX/arch" -H "X-aws-proxy-auth: $TOKEN_x86"
{"uname_m":"x86_64","process_arch":"x64"}
For reference, if you build from the same Dockerfile without --cpu-configurations, you get an Arm image.
aws lambda-microvms create-microvm-image --name devio-x86-test-default --code-artifact uri=s3://amzn-s3-demo-bucket/app.zip --base-image-arn arn:aws:lambda:ap-northeast-1:aws:microvm-image:al2023-1 --build-role-arn arn:aws:iam::123456789012:role/MicroVMBuildRole
The cpuConfigurations in the response was ARM_64, and baseImageVersion was 3.1, the same as x86.
"cpuConfigurations": [
{
"architecture": "ARM_64"
}
],
This is the result of calling /arch on the MicroVM launched from this Arm image. EA and TOKEN_default are that MicroVM's endpoint and authentication token.
$ curl -sS -m 30 "https://$EA/arch" -H "X-aws-proxy-auth: $TOKEN_default"
{"uname_m":"aarch64","process_arch":"arm64"}
Here is the full source of the app used for verification.
app.js
// 検証用: アーキテクチャと実行環境の CPU・メモリを返す HTTP サーバー(ポート 8080)。
// 読むのは固定のファイルと固定の API だけ。リクエストの内容はパスの分岐にしか使わない。
// 環境変数と /proc/self/environ は読まない。ホスト名は返さない。
const http = require('http');
const os = require('os');
const fs = require('fs');
const { execFileSync } = require('child_process');
const read = (p) => {
try { return fs.readFileSync(p, 'utf8'); } catch (e) { return `ERROR: ${e.code}`; }
};
// /proc/cpuinfo は先頭 1 コアのブロックと、コア数だけ返す。
const CPU_KEYS_X86 = ['vendor_id', 'cpu family', 'model', 'model name', 'stepping', 'microcode', 'cpu MHz', 'cache size', 'flags'];
const CPU_KEYS_ARM = ['BogoMIPS', 'Features', 'CPU implementer', 'CPU architecture', 'CPU variant', 'CPU part', 'CPU revision'];
const cpuinfo = () => {
const text = read('/proc/cpuinfo');
const blocks = text.split(/\n\s*\n/).filter((b) => b.trim());
const first = {};
for (const line of (blocks[0] || '').split('\n')) {
const i = line.indexOf(':');
if (i < 0) continue;
const k = line.slice(0, i).trim();
const v = line.slice(i + 1).trim();
if (CPU_KEYS_X86.includes(k) || CPU_KEYS_ARM.includes(k)) first[k] = v;
}
const flags = (first.flags || '').split(/\s+/).filter(Boolean);
const feats = (first.Features || '').split(/\s+/).filter(Boolean);
return {
processorBlocks: blocks.length,
first,
x86FlagCount: flags.length,
x86Flags: flags.filter((f) => /^(avx|avx2|avx512.*|sse4_2|amx.*|vnni|avx_vnni|bmi2|sha_ni|vaes|vpclmulqdq|gfni|rdrand|rdseed|adx|fma|erms|fsrm|serialize|tsxldtrk|ibrs|ibpb|stibp|ssbd|md_clear|hypervisor)$/.test(f)),
armFeatureCount: feats.length,
};
};
const meminfo = () => {
const out = {};
for (const line of read('/proc/meminfo').split('\n')) {
const m = line.match(/^(MemTotal|MemFree|MemAvailable|SwapTotal|SwapFree):\s+(\d+) kB/);
if (m) out[m[1]] = `${m[2]} kB`;
}
return out;
};
const status = () => {
const out = {};
for (const line of read('/proc/self/status').split('\n')) {
const m = line.match(/^(Cpus_allowed_list|Cpus_allowed|Mems_allowed_list):\s+(.*)$/);
if (m) out[m[1]] = m[2];
}
return out;
};
const osRelease = () => {
const out = {};
for (const line of read('/etc/os-release').split('\n')) {
const m = line.match(/^(PRETTY_NAME|NAME|VERSION|VERSION_ID|ID)=(.*)$/);
if (m) out[m[1]] = m[2].replace(/^"|"$/g, '');
}
return out;
};
const report = () => {
const cpus = os.cpus();
return {
uname_m: execFileSync('uname', ['-m']).toString().trim(),
node: { version: process.version, arch: process.arch, platform: process.platform },
os: { release: os.release(), version: os.version(), type: os.type(), machine: os.machine() },
procVersion: read('/proc/version').trim(),
osRelease: osRelease(),
vcpu: {
availableParallelism: os.availableParallelism(),
osCpusLength: cpus.length,
osCpusModel: cpus.length ? cpus[0].model : null,
osCpusSpeedMHz: cpus.length ? cpus[0].speed : null,
...status(),
},
cpuinfo: cpuinfo(),
memory: { ...meminfo(), osTotalmemBytes: os.totalmem(), osFreememBytes: os.freemem() },
};
};
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
if (req.url === '/arch') {
res.end(JSON.stringify({ uname_m: execFileSync('uname', ['-m']).toString().trim(), process_arch: process.arch }) + '\n');
} else if (req.url === '/env-report') {
res.end(JSON.stringify(report(), null, 2) + '\n');
} else {
res.end(JSON.stringify({ status: 'ok' }) + '\n');
}
});
server.listen(8080, () => {
console.log('Listening on port 8080');
});
Checking CPU and memory
I retrieved the MicroVM's CPU and memory information from the app's /env-report. The values come from /proc/cpuinfo, /proc/meminfo, /proc/self/status, and Node.js's os module.
CPU
The vCPU count was 4 on both Arm and x86. Node.js's availableParallelism and the processor count in /proc/cpuinfo were 4, and Cpus_allowed_list was 0-3.
In the build information for the image specified as x86 (get-microvm-image-build), the chipset was INTEL. There were two builds, and chipsetGeneration was icelake and sapphirerapids. When I launched four x86 MicroVMs from the same image, the CPUs were also split into two types, two each.
| Generation | model | stepping | model name | cache size | Generation-specific instructions | Count |
|---|---|---|---|---|---|---|
| Sapphire Rapids | 143 | 8 | Intel(R) Xeon(R) Processor | 107520 KB | AMX, avx_vnni, avx512_fp16 present | 2 |
| Ice Lake | 106 | 6 | Intel(R) Xeon(R) Processor @ 2.90GHz | 55296 KB | AMX, avx_vnni, avx512_fp16 absent | 2 |
The model name of the MicroVM conceals the model number. So I compared it against the /proc/cpuinfo values in DevelopersIO's measurement articles on M6i and M7i.
The MicroVM with model 106 matched the M6i article in model, stepping, and cache size (55296 KB), and likewise had no AMX-family instructions. The MicroVM with model 143 matched the M7i article in model, stepping, and cache size (107520 KB). It also had AMX, avx_vnni, and avx512_fp16, as in that article.
Memory
The default baseline is 2 GB / 1 vCPU. In the MicroVMs I launched this time with the default size, both Arm and x86 showed 4 vCPUs and about 8 GB of memory. Swap (SwapTotal) was 0 on both.
| Item | Arm | x86 |
|---|---|---|
| MemTotal | 8209056 kB | 8222748 kB |
| os.totalmem() | 8406073344 bytes | 8420093952 bytes |
The pricing page states that the peak is up to 4 times the baseline. The 4 vCPUs seen equal this upper limit (1 vCPU × 4), and the roughly 8 GB of memory is close to the upper limit (2 GB × 4). You are billed for the baseline portion plus the amount actually used beyond the baseline.
Pricing
The unit prices that differ between Arm and x86 are vCPU-seconds and memory GB-seconds. The unit prices for the Tokyo region are as follows.
| Item | Arm (USD) | x86 (USD) | Difference |
|---|---|---|---|
| vCPU-second | 0.0000322421 | 0.0000371569 | +15.24% |
| Memory GB-second | 0.0000042688 | 0.0000049195 | +15.24% |
In the US East (N. Virginia) region, x86 is 17.91% more expensive for both vCPU-seconds and memory GB-seconds.
Summary
Lambda MicroVMs now supports x86 from base image version 3 onward.
If you want to use x86 binaries or libraries, or if your development environment is x86 and cross-compiling for Arm was taking a lot of build time, give the x86 image a try.
However, the execution unit price is about 15% higher than Arm in the Tokyo region and about 18% higher in N. Virginia. I also confirmed that the CPU generations allocated can be mixed.
For workloads that do not depend on the CPU architecture, I recommend sticking with the default Arm.
