Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••••
Windows Tipps & SecurityWindows 11 Premium: System schneller, schöner und besser machen(02.10.2026 um 16:30 Uhr)
••
IT NachrichteniOS 27 macht Probleme: Dieses Update schafft Abhilfe(02.10.2026 um 16:57 Uhr)
••••••••
Windows Tipps & SecurityWindows 11 Premium: System schneller, schöner und besser machen(02.10.2026 um 16:30 Uhr)
••
IT NachrichteniOS 27 macht Probleme: Dieses Update schafft Abhilfe(02.10.2026 um 16:57 Uhr)
••••
Intelligence View
⚡ tsecurity.de Intelligence

Serverless image pipeline with aws lambda+node+wasm: from 11.5mb to 91.2kb

A while back I needed to process thousands of images for an e-commerce platform: multiple versions per product, carousel, thumbnail, invoice miniature. Manual…

Beitrag
0
Seite
0
↗ Quelle (dev.to)
Social ReaktionenReagiere als Erste:r — dein Feedback zählt!

A while back I needed to process thousands of images for an e-commerce platform: multiple versions per product, carousel, thumbnail, invoice miniature. Manual processing wasn't an option. The bash scripts I ran from my machine worked, but they depended on me to run them. The solution was clear: a cloud pipeline that triggered automatically every time a new image arrived.



This post is about how I built that pipeline on AWS Lambda using beautiful-image, and why WASM was the key decision that made everything fit together without friction.






The architecture



The flow is simple and completely serverless:





No servers to maintain, no workers to scale, no queues to configure for the basic case. One image comes in, two variants come out, ready to serve from CloudFront.






Why WASM changes everything



beautiful-image has a core written in Rust compiled to WASM. That means:





  • Single artifact: the 469KB WASM binary goes inside the same Lambda ZIP. No Layers, no Docker images.


  • Real portability: the same package runs on nodejs22.x with x86_64 or arm64 architecture without recompiling anything.


  • Zero native dependencies: npm install is enough. Nothing to compile.



The deploy comes down to three commands:




npm install
sam build
sam deploy







The implementation



The handler is straightforward. It downloads the image from S3, generates the variants with beautiful-image, and uploads them to the destination bucket:



import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"
import { image } from "beautiful-image/node"
import path from "node:path"

const SOURCE_BUCKET = process.env.SOURCE_BUCKET!
const DEST_BUCKET = process.env.DEST_BUCKET!

const s3 = new S3Client({})

const VARIANTS = [
{ folder: "optimized", width: 800, quality: 80 },
{ folder: "thumbnails", width: 200, quality: 80 },
] as const

const ALLOWED_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".webp"])

export const handler = async (event: AWSLambda.S3Event): Promise<void> => {
for (const record of event.Records) {
const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, " "))

const ext = path.extname(key).toLowerCase()
if (!ALLOWED_EXTENSIONS.has(ext)) {
console.log(`Skipping unsupported file type: ${key}`)
continue
}

const t0 = performance.now()
console.log(`Processing: ${key}`)

let input: Buffer
try {
const t1 = performance.now()
const { Body } = await s3.send(
new GetObjectCommand({ Bucket: SOURCE_BUCKET, Key: key })
)
if (!Body) {
console.error(`Empty body for key: ${key}`)
continue
}
input = Buffer.from(await Body.transformToByteArray())
console.log(`[timer] download: ${(performance.now() - t1).toFixed(0)}ms ${input.length}B`)
} catch (err) {
console.error(`Failed to download ${key}:`, err)
continue
}

const filename = path.parse(key).name

for (const { folder, width, quality } of VARIANTS) {
const tp = performance.now()
let result: Awaited<ReturnType<ReturnType<typeof image>["toJpeg"]>>
try {
result = await image(input).resize(width).toJpeg(quality)
} catch (err) {
console.error(`Failed to process variant ${folder} for ${key}:`, err)
continue
}
console.log(`[timer] wasm ${folder} (${width}px): ${(performance.now() - tp).toFixed(0)}ms`)

const destKey = `${folder}/${filename}.jpg`
const tu = performance.now()
try {
await s3.send(
new PutObjectCommand({
Bucket: DEST_BUCKET,
Key: destKey,
Body: result.data,
ContentType: "image/jpeg",
})
)
} catch (err) {
console.error(`Failed to upload ${destKey}:`, err)
continue
}
console.log(`[timer] upload ${destKey}: ${(performance.now() - tu).toFixed(0)}ms`)

console.log(
`Saved ${destKey} - ${result.originalSize}B → ${result.optimizedSize}B (${Math.round(result.compressionRatio * 100)}% smaller)`
)
}

console.log(`[timer] total: ${(performance.now() - t0).toFixed(0)}ms`)
}
}





examples/lambda-demo



The beautiful-image API is chainable and reads like what it does: download, resize, compress, done.



const result = await image(input).resize(800).toJpeg(80)
// result.data Buffer ready to upload
// result.originalSize original size in bytes
// result.optimizedSize new size in bytes
// result.compressionRatio 0.99 = 99% smaller







The SAM template



The entire stack in ~64 lines of YAML. The Lambda fires on any s3:ObjectCreated event in the source bucket:



AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Beautiful Image processor Lambda triggered by S3 uploads using beautiful-image

Parameters:
SourceBucketName:
Type: String
Default: "my-raw-images"
Description: S3 bucket where raw images are uploaded (trigger source)
DestBucketName:
Type: String
Default: "my-processed-images"
Description: S3 bucket where processed variants are saved
Environment:
Type: String
Default: sandbox
Description: Deployment environment name

Resources:
ImageProcessorFunction:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: esbuild
BuildProperties:
Minify: true
Target: es2020
Sourcemap: true
EntryPoints:
- handler.ts
External:
- '@aws-sdk/*'
Properties:
FunctionName: !Sub "ImageProcessorFunction-${Environment}"
CodeUri: ./
Handler: handler.handler
Runtime: nodejs22.x
Timeout: 60
MemorySize: 1769
Environment:
Variables:
SOURCE_BUCKET: !Ref SourceBucketName
DEST_BUCKET: !Ref DestBucketName
Policies:
- Statement:
- Effect: Allow
Action:
- s3:GetObject
Resource: !Sub "arn:aws:s3:::${SourceBucketName}/*"
- Effect: Allow
Action:
- s3:PutObject
Resource: !Sub "arn:aws:s3:::${DestBucketName}/*"

ImageProcessorFunctionS3Permission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt ImageProcessorFunction.Arn
Action: lambda:InvokeFunction
Principal: s3.amazonaws.com
SourceArn: !Sub "arn:aws:s3:::${SourceBucketName}"
SourceAccount: !Ref AWS::AccountId





examples/lambda-demo



The MemorySize of 1769MB is not arbitrary: it's exactly 1 vCPU on Lambda. WASM is single-threaded, so adding more memory doesn't speed up processing, but going below that threshold does slow it down.



The S3 SDK is marked as External because the nodejs22.x runtime already includes it, so there's no need to bundle it.





The result








<video src="https://github.com/user-attachments/assets/5a3bc4b0-c88d-4504-965e-6c54bea3b6d7" autoplay="" muted="" loop="" playsinline=""></video>



One image lands in the bucket. The pipeline generates:





  • optimized/: 800px, ready for the product detail page


  • thumbnails/: 200px, ready for the carousel and invoices


  • ...others/: additional variants (e.g. 400px, 600px)



No manual intervention, no servers to maintain.






When to use beautiful-image vs Sharp?



The de facto library for this in Node.js is Sharp. Excellent tool, but it introduces friction on Lambda: it uses native binaries compiled against libvips (~20MB), those binaries must match the exact Lambda architecture, and deploying the wrong binary means a runtime failure. The official Sharp docs for Lambda dedicate entire sections to platform flags, cross-compilation, and pnpm symlink issues. The practical solution the docs end up suggesting: use a community-maintained Lambda Layer.



beautiful-image doesn't compete with Sharp on raw speed. Sharp delegates to libvips, a C library with decades of architecture-specific optimizations that WASM can't fully match.



If you need compositing, SVG rendering, RAW formats, or color space conversion: Sharp is the right tool and nothing comes close. If you need resize and web optimization with a handful of filters and want the deploy to be a non-issue, beautiful-image gets you there with a fraction of the weight and zero operational friction.



The full code with SAM template, test event, and configuration is at examples/lambda-demo.

🔍 CTI & Forensik

Cyber Threat Intelligence & Forensik

ATT&CK-Navigator · IoC-Radar · Exploit-Belege
CTI Threat Relationship Graph
Akteure · Techniken · Beziehungen
2 Knoten · 1 Relationen
CVE / Incident Threat Actor Software MITRE ATT&CK CWE Weakness IoC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Serverless image pipeline with aws lambda+node+wasm: from 11.5mb to 91.2kb

Thematisch verwandte Begriffe: Serverless, image, pipeline, with · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag