How to Upload to S3 from a Lambda (boto3)

A Lambda that saves an upload to S3 is one put_object call - the catch is decoding the request body (API Gateway delivers it base64-encoded) and giving the function s3:PutObject. Here's the handler.

Backend Engineerawss3lambda

The flow

A form posts a file to API Gateway, which invokes a Lambda. The Lambda's one job: write the bytes to S3 under the given key. The two things to get right are decoding the body and the IAM permission.

The handler

import base64
import boto3

BUCKET = "user-uploads"
s3 = boto3.client("s3")

def handler(event, context=None):
    key = event["key"]
    body = base64.b64decode(event["body_b64"])   # API Gateway sends binary base64-encoded
    s3.put_object(Bucket=BUCKET, Key=key, Body=body, ContentType="image/png")
    return {"statusCode": 200, "key": key}

put_object writes the object in one call - no temp files, no multipart needed for normal image sizes.

The gotchas

Reuse the client

Create the boto3.client("s3") at module scope (outside handler), not inside it - Lambda reuses the warm container across invocations, so the client is created once and connection setup is amortized.

For large files

For big uploads, skip the Lambda body entirely: hand the client a presigned PUT URL and let it upload straight to S3. The Lambda only mints the URL - it never touches the bytes, which dodges Lambda's payload size limits.

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

How do I upload a file to S3 from a Lambda?

Call s3.put_object(Bucket=..., Key=..., Body=bytes, ContentType=...) with boto3. Decode the incoming body first (API Gateway sends binary uploads base64-encoded) and give the function's role s3:PutObject.

Why is my Lambda S3 upload AccessDenied?

The Lambda execution role is missing s3:PutObject on the bucket (arn:aws:s3:::your-bucket/*). Add that permission to the role's policy.

How do I upload large files to S3 via Lambda?

Don't pass big files through the Lambda - have it return a presigned PUT URL and let the client upload directly to S3. That avoids Lambda's request/response payload limits.

Keep learning

Return the Correct HTTP Status CodeBackend projectRepair Broken API PaginationBackend projectAdd CORS Middleware to an Express APIBackend projectBackend roadmapStep by step to hiredBackend interview questionsSTAR answersAll Backend projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →