Lambda Multi-Arch Builds: arm64 CI Matrices That Actually Ship

Lambda Multi-Arch Builds: arm64 CI Matrices That Actually Ship
13 views
Flipping x86_64 Lambdas to “save money on Graviton” fails when node-gyp artifacts from Ubuntu-x64 CI get uploaded to arm64 functions. The unfair advantage is a CI matrix that rebuilds native modules for each target, verifies with file/readelf, and refuses to publish a mismatched zip.
⚡ TL;DR: Build per architecture (x86_64, arm64) with matching Lambda container images or npm rebuild --arch. Set function Architectures explicitly in IaC. Fail the pipeline if a .node binary ELF machine type does not match. Prefer pure-JS deps when possible. Align runtime choices with Lambda Warm Pools and keep secrets out of builds via Secret-Aware Context Filters.

Lambda Multi-Arch Builds: production guidance

yaml
# .github/workflows/lambda-multiarch.yml
strategy:
 matrix:
 arch: [x86_64, arm64]
 include:
 - arch: x86_64
 platform: linux/amd64
 lambda_arch: x86_64
 - arch: arm64
 platform: linux/arm64
 lambda_arch: arm64
jobs:
 build:
 runs-on: ubuntu-latest
 steps:
 - uses: docker/setup-qemu-action@v3
 - uses: docker/setup-buildx-action@v3
 - name: Build inside Lambda Node 20 image
 run: |
 docker run --rm --platform=${{ matrix.platform }} \
 -v "$PWD":/var/task -w /var/task \
 public.ecr.aws/lambda/nodejs:20 \
 bash -lc "npm ci && npm run build && npm prune --omit=dev"
 - name: Assert ELF arch
 run: ./scripts/assert-native-arch.sh ${{ matrix.lambda_arch }}
 - run: (cd dist && zip -r ../fn-${{ matrix.lambda_arch }}.zip .)
bash
# scripts/assert-native-arch.sh
#!/usr/bin/env bash
set -euo pipefail
want="$1" # x86_64 | arm64
while IFS= read -r -d "" f; do
 info=$(file "$f")
 case "$want" in
 arm64) echo "$info" | grep -q "ARM aarch64" ;;
 x86_64) echo "$info" | grep -q "x86-64" ;;
 esac || { echo "arch mismatch: $f ($info)"; exit 1; }
done < <(find node_modules dist -name "*.node" -print0 2>/dev/null)
✅ Build inside the Lambda base image for that arch.
❌ npm ci on GitHub’s x64 runner then deploy to arm64.

IaC must pin Architectures

typescript
new lambda.Function(this, "Api", {
 runtime: lambda.Runtime.NODEJS_20_X,
 architecture: lambda.Architecture.ARM_64,
 code: lambda.Code.fromAsset(`artifacts/fn-arm64.zip`),
 handler: "index.handler",
});
typescript
// BAD: default arch in one stack, zip built for another
new lambda.Function(this, "Api", {
 runtime: lambda.Runtime.NODEJS_20_X,
 code: lambda.Code.fromAsset("fn.zip"), // mystery arch
 handler: "index.handler",
});
Dual-arch publish (two functions or two versions) only if you need gradual migration — do not ship a fat zip with both and hope.

Native module escape hatches

Dep type Strategy
Pure JS Prefer; simplest
Prebuilt *-linux-arm64 wheels/binaries Pin optionalDependencies carefully
Custom C++ addons Rebuild in Lambda container per arch
Sharp / bcrypt / better-sqlite3 Always matrix-test both arches

Closing checklist

  • [ ] CI matrix builds x86_64 and/or arm64 in Lambda base images
  • [ ] assert-native-arch gate on *.node ELF types
  • [ ] Function Architectures set in IaC to match artifact
  • [ ] Smoke invoke on the target arch before prod promote
  • [ ] Document which native deps force matrix complexity
  • [ ] Cost note: Graviton savings vs CI minutes tracked

Related reading

Last updated on September 11, 2026 Related: Lambda on ARM64 Graviton3: 34% Cheaper and 20% Faster Than x86; Lambda Code Signing: Enforce CI-Built Artifacts in Every Account; Cursor Agent Mode: Multi-File Refactors That Survive CI Gates.

Watch: 100 Days of AI on YouTube

Short videos from CheatCoders, one AI engineering topic per day.

Open the playlist on YouTube · CheatCoders on YouTube

Deep-dive PDF

Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.

Already subscribed? or open the subscribe page.


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a comment

No account needed. Name and email are optional.