We’ll create an event-driven Lambda that listens for new images in an S3 bucket (photos-raw
), resizes them using Node.js, and saves the output to another bucket (photos-resized
).
You’ll learn how to:
- Configure S3 trigger events in AWS SAM
- Resize images in Lambda using sharp
📝 template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Timeout: 29
Runtime: nodejs22.x
MemorySize: 512
Resources:
ResizeFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/resize.handler
Policies:
- S3ReadPolicy:
BucketName: !Sub "photos-raw-${AWS::AccountId}"
- S3WritePolicy:
BucketName: !Sub "photos-resized-${AWS::AccountId}"
Events:
S3Upload:
Type: S3
Properties:
Bucket: !Sub "photos-raw-${AWS::AccountId}"
Events: s3:ObjectCreated:Put
Environment:
Variables:
RESIZED_BUCKET: !Sub "photos-resized-${AWS::AccountId}"
RawBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "photos-raw-${AWS::AccountId}"
ResizedBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "photos-resized-${AWS::AccountId}"
Whenever someone uploads a new file to the photos-raw S3 bucket, automatically trigger (run) the Lambda function.
🧠 Function
import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
import sharp from 'sharp';
import { S3Event } from 'aws-lambda';
import { Readable } from 'stream';
const s3 = new S3Client({});
const RESIZED_BUCKET = process.env.RESIZED_BUCKET
const streamToBuffer = async (stream: Readable): Promise<Buffer> => {
const chunks: Uint8Array[] = [];
for await (const chunk of stream) chunks.push(chunk);
return Buffer.concat(chunks);
};
export const handler = async (event: S3Event) => {
for (const record of event.Records) {
const bucket = record.s3.bucket.name;
const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' '));
const { Body } = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
if (!Body || !(Body instanceof Readable)) {
console.error('Invalid body stream');
return;
}
const imageBuffer = await streamToBuffer(Body);
const resized = await sharp(imageBuffer)
.resize(800)
.toBuffer();
await s3.send(new PutObjectCommand({
Bucket: RESIZED_BUCKET,
Key: key,
Body: resized,
ContentType: resized.ContentType,
}));
}
};
Conclusion
You've now built an event-driven image pipeline using:
- 🪣 S3 Triggers
- 🧠 AWS SAM for infrastructure as code
- ⚙️ Sharp for image processing
Top comments (0)