Course outline

15.1

AWS Lambda Basics and Pricing

Functions vs servers, invocation types, triggers, runtimes and container images, and the pricing maths.

22 min Reading + animations

Tip: tap or hover any dotted-underlined term to see what it means.

By the end of this lesson you will be able to

  • Say what “serverless” really means (no servers to manage, pay per use, scale to zero) and name the main serverless services on AWS and what each one is for.
  • Compare an always-on EC2 instance with a Lambda function: how each runs, scales and is billed, and when each one is the better choice (including the 15-minute limit).
  • Describe how a function runs (handler, event, execution environment, cold and warm starts), pick a runtime from the current list, and know when to ship a function as a container image.
  • Tell the three invocation types apart (synchronous, asynchronous, event source mapping) and predict who retries a failure and where a failed event ends up (destinations, dead-letter queues, the queue’s own DLQ).
  • Give a function the right permissions: the execution role for what it calls, the resource-based policy for who may call it; expose it with a function URL; release it safely with versions and aliases.
  • Build the two classic examples (thumbnails on S3 upload, a serverless cron with EventBridge) and calculate a monthly Lambda bill from requests and GB-seconds, then compare it with an EC2 instance.

#What serverless means

For four chapters you have been running things on servers: EC2 instances you size, patch and scale (chapter 4), databases on instances you pick (chapter 7), containers on EC2 or Fargate (chapter 14). Every one of them is billed while it is up, whether it works or waits.

Serverless is a different deal. You hand AWS your code (or your data) and AWS runs it when it is needed. Three things make a service serverless:

  1. No servers to manage. There are servers, of course, but you never see, size, patch or replace them. Serverless does not mean “no servers”; it means “not your servers”.
  2. Pay per use. You pay per request, per millisecond of run time, per GB stored, per message. Nothing is billed for idle capacity.
  3. Scales automatically, down to zero. Ten requests a day or ten thousand a second, the service grows and shrinks on its own; with no traffic, nothing runs and nothing is billed.

The idea started with FaaS (Function as a Service): you upload a function, the platform runs it for each event. AWS Lambda (launched 2014) pioneered it. Today “serverless” covers any fully managed service with those three properties: databases, queues, storage, APIs, workflows.

#The serverless menu on AWS

The exam treats these services as “serverless”. Each one is taught in its own lesson; this table is your map.

ServiceWhat it does without serversWhere it is taught
AWS LambdaRuns your code for each event; pay per request and per millisecondThis lesson, 15.2 (limits, concurrency), 15.3 (networking)
Amazon DynamoDBNoSQL key-value database; on-demand mode bills per requestLesson 15.4, 15.5
Amazon API GatewayManaged HTTP, REST and WebSocket APIs in front of Lambda and other backendsLesson 15.6
Amazon S3Object storage, also static websites; pay per GB and requestChapter 10
Amazon SNS and SQSPub/sub topics and message queuesLessons 13.1–13.4
Amazon Data Firehose (was Kinesis Data Firehose)Loads streaming data into S3, Redshift, OpenSearch and moreLesson 13.6
Aurora Serverless v2Aurora whose capacity grows and shrinks with load (can pause at 0 capacity)Lesson 7.3
AWS Step FunctionsWorkflows (state machines) that chain Lambda and other servicesLesson 15.7
AWS FargateRuns containers without EC2 instancesLesson 14.2
Amazon CognitoSign-up and sign-in for app users, and temporary AWS credentials for themLesson 15.7
Amazon EventBridgeEvent bus and scheduler that routes events to targets such as LambdaBelow, and lesson 19.5

A typical serverless web app combines them: static files in S3 (served by CloudFront), users signing in with Cognito, a REST API in API Gateway that calls Lambda functions, and DynamoDB storing the data. Lesson 15.8 builds exactly that.

#Why Lambda: an always-on server vs a function per request

Amazon EC2AWS Lambda

  • Virtual servers in the cloud; you pick the instance type.
  • Limited by the instance’s CPU and RAM.
  • Runs continuously, so it is billed every second it is up, busy or idle.
  • Scaling means action: an Auto Scaling group launches or terminates instances, which takes minutes.
  • Any run time: a process can run for months.
  • You patch the OS, rotate AMIs and place instances in several AZs.
  • Functions: no servers to see or manage.
  • Limited by time: one invocation runs at most 15 minutes.
  • Runs on demand, only when an event arrives; billed per request and per millisecond of run time.
  • Scaling is automatic: each concurrent request gets its own execution environment within seconds.
  • Up to 10,240 MB of memory per function, CPU in proportion.
  • AWS patches the runtime and spreads environments across AZs for you.

An always-on server or a function per request

The product-search API of a Dhaka e-commerce shop, built twice: on EC2 instances in an Auto Scaling group (left) and as a Lambda function (right). Watch what each does at night, in the morning, during a flash sale, and with a job that runs for 40 minutes.

Scenario

No requests: the instance is still billed, Lambda costs nothing.

EC2 Auto Scaling group
Lambda (AWS-managed)
Shoppers
Instance 1idle, billed
Step 1 of 2
1

It is 3 a.m. and nobody is shopping. Instance 1 is running anyway, because a server must be up before the first request arrives. You pay for every hour it runs, busy or idle.

Each execution environment handles one request at a time. Ten simultaneous requests need ten environments; this number is the function’s concurrency. An account starts with 1,000 concurrent executions per Region, shared by all its functions. Scaling, throttling and cold starts get a full lesson: lesson 15.2.

#Benefits of Lambda

  • Simple pricing: pay per request and per GB-second of compute, with a monthly free tier of 1 million requests and 400,000 GB-seconds (details below).
  • Integrated with the whole AWS platform: dozens of services can invoke a function directly (next sections).
  • Many languages: Node.js, Python, Java, .NET, Ruby, and anything else through an OS-only runtime or a container image.
  • Monitoring built in: every function sends its logs to CloudWatch Logs and its metrics (invocations, errors, duration, throttles, concurrency) to CloudWatch without any agent; AWS X-Ray adds tracing.
  • More resources are one setting away: memory from 128 MB to 10,240 MB. CPU grows with memory: at 1,769 MB a function has the equivalent of one vCPU, and at 10,240 MB up to six vCPUs. A CPU-bound function often finishes so much faster with more memory that it costs the same or less.

The slides add that more RAM also gives more network bandwidth. Today each execution environment gets 625 Mbps; for functions outside a VPC you can request an increase, after which bandwidth scales with memory from 2,048 MB up to about 3,000 Mbps at 10,240 MB.

#How a function runs

A function is your code plus its configuration (runtime, memory, timeout, environment variables, execution role). The entry point is the handler, a function that Lambda calls with two arguments: the event (what happened, as JSON) and the context (request ID, remaining time, memory limit).

import json, os, boto3

s3 = boto3.client("s3")              # init code: runs once per environment
TABLE = os.environ["TABLE_NAME"]     # configuration from environment variables

def handler(event, context):         # runs once per invocation
    record = event["Records"][0]["s3"]
    key = record["object"]["key"]
    print(f"resizing {key}, {context.get_remaining_time_in_millis()} ms left")
    return {"status": "ok", "key": key}

When a request arrives and no environment is free, Lambda creates one: it starts a microVM, downloads your code, starts the runtime and runs your init code (everything outside the handler). This is a cold start, typically 100 ms to a second or more depending on the runtime and package size. Then it calls the handler. When the handler returns, the environment stays warm for a while and the next request skips straight to the handler. That is why you create SDK clients and database connections outside the handler: they are reused across warm invocations. Lesson 15.2 covers cold starts, provisioned concurrency and SnapStart.

Anything stored in memory or in /tmp (512 MB by default, up to 10,240 MB) may survive to the next invocation on the same environment, but there is no guarantee: treat each invocation as stateless and keep state in DynamoDB, S3 or a cache.

#Runtimes

The slides list the languages as Node.js, Python, Java, C# / PowerShell, Ruby and a custom runtime. That is still the right shape, but the versions change every year. The managed runtimes supported in October 2026:

LanguageRuntime identifiers (supported)Notes
Node.jsnodejs22.x, nodejs24.xNode.js 26 in preview; Node.js 18 and 20 are deprecated
Pythonpython3.11 to python3.143.10 deprecation scheduled for 31 October 2026; 3.9 deprecated 15 December 2025
Javajava21, java25; Java 8, 11 and 17 on Amazon Linux 2023 (java17.al2023…)Java is where SnapStart started (lesson 15.2)
.NET (C#, PowerShell)dotnet8, dotnet10PowerShell scripts run on the .NET runtime; “.NET Core” in the slides is the old name
Rubyruby3.3, ruby3.4, ruby4.0
OS-onlyprovided.al2023For Go, Rust, C++ or any language: you bring a runtime client that talks to the Lambda Runtime API

Two corrections to the slides: the managed Go 1.x runtime was retired in January 2024, so Go now runs on the OS-only runtime; and the old Amazon Linux 2 based runtimes (provided.al2, Python 3.10/3.11, Java on Amazon Linux 2) are at or near their end because Amazon Linux 2 itself reached end of life in June 2026. When a runtime is deprecated, AWS stops patching it; after a grace period you can no longer create, then no longer update, functions that use it. Every supported runtime runs on both x86_64 and arm64 (Graviton).

#Container images

Instead of a .zip file (50 MB zipped when uploaded directly, 250 MB unzipped including layers), you can package a function as a container image of up to 10 GB, stored in Amazon ECR (lesson 14.1). This suits big dependencies (machine learning libraries, headless browsers) and teams that already build everything with Docker.

The catch from the slides still holds: the image must implement the Lambda Runtime API, the small HTTP interface through which a function fetches its next event and posts its result. The AWS base images (public.ecr.aws/lambda/python:3.13 and so on) include it; for your own base image you add the open-source runtime interface client. The runtime interface emulator lets you test the image locally. A function is still a function: 15 minutes, one request per environment, invoked by events.

FROM public.ecr.aws/lambda/python:3.13
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py ${LAMBDA_TASK_ROOT}
CMD ["app.handler"]

So when the exam says “run an existing, arbitrary Docker image” (a web server that listens on a port, a long-running worker), the answer is ECS or EKS on Fargate, not Lambda.

#What can invoke a function

The slides’ list of main integrations, with how each one invokes (the next section explains the three types):

SourceHow it invokesTypical use
API GatewaySynchronousREST or HTTP API backend (lesson 15.6)
Application Load BalancerSynchronousLambda as an ALB target (lesson 6.3)
Function URLSynchronousA simple HTTPS endpoint for one function
CognitoSynchronousUser pool triggers: custom checks at sign-up, after sign-in…
CloudFrontSynchronousLambda@Edge, taught in lesson 11.3
S3AsynchronousProcess uploads (lesson 10.7)
SNSAsynchronousFan-out: one message to several functions (lesson 13.4)
EventBridge (rules and Scheduler)AsynchronousReact to AWS events, run on a schedule; “CloudWatch Events” in the slides is its old name
CloudWatch LogsAsynchronousSubscription filter: process log lines as they arrive
SQSEvent source mappingWork queue with a buffer (lesson 13.1)
Kinesis Data StreamsEvent source mappingOrdered stream processing per shard (lesson 13.5)
DynamoDB StreamsEvent source mappingReact to table changes (lesson 15.5)
Data FirehoseSynchronousTransform records before delivery (lesson 13.6)

Event source mappings also read Amazon MSK and self-managed Kafka, Amazon MQ and DocumentDB change streams. And any program can call the Invoke API with the SDK or CLI.

#Three ways to invoke a function

Every invocation is one of three types, and the type decides who waits, who retries and where failures go. The exam loves this.

Three ways to invoke a function

The same order-processing function of the Dhaka shop, invoked synchronously by API Gateway, asynchronously by S3, and through an event source mapping that polls an SQS queue. Who waits, who retries, and where do failed events go?

Scenario

The caller waits for the result; errors come straight back to it.

CallerAPI Gateway · S3
SQS queue
Lambda service
Function code
Destination / DLQ
Invoke (RequestResponse)
Step 1 of 4
1

A shopper taps “Place order”. API Gateway calls Invoke with the invocation type RequestResponse and keeps the HTTP connection open: it needs the answer to reply to the phone.

Synchronous (RequestResponse). The caller waits for the result. Payloads up to 6 MB each way (response streaming allows up to 200 MB). Errors go straight back to the caller and Lambda does not retry: the caller (the SDK, the client app) decides. A throttled call gets 429 TooManyRequestsException at once.

Asynchronous (Event). The caller hands the event to Lambda and gets 202 immediately; Lambda keeps the event in an internal queue and invokes the function. The event can be up to 1 MB (raised from 256 KB in 2025). On a function error Lambda retries twice by default (after about 1 minute, then about 2 more), configurable to 0 or 1; throttled events are kept and retried for up to the maximum event age (60 seconds to 6 hours, default 6 hours). What then?

  • Destinations: send a record of the invocation to a target on success or on failure. Targets: SQS, SNS, EventBridge, another Lambda function, and (on failure only, since November 2024) an S3 bucket. The record includes the request, the response or error, and the reason. Preferred today.
  • Dead-letter queue (DLQ): the older mechanism; an SQS queue or SNS topic set on the function that receives only the failed event, no error details.
  • Neither: the event is discarded. Because the internal queue is eventually consistent, an event can also be delivered more than once, so make the code idempotent.

Event source mapping (polling). For SQS, Kinesis, DynamoDB Streams and Kafka, nobody pushes events to Lambda; the Lambda service runs pollers that read the source and invoke the function synchronously with a batch. Failure handling depends on the source:

  • SQS: failed messages stay in the queue, reappear after the visibility timeout and are retried; after maxReceiveCount the queue’s own redrive DLQ takes them. Return partial batch responses (ReportBatchItemFailures) so one bad message does not make the whole batch retry. Set the visibility timeout to at least six times the function timeout.
  • Kinesis and DynamoDB Streams: records are processed in order per shard, so a failing batch blocks its shard until it succeeds or the records expire. Limit it with maximum retry attempts, maximum record age and bisect batch on error, and send what is skipped to an on-failure destination (SQS, SNS or S3).
SynchronousAsynchronousEvent source mapping
Who invokesThe caller, and it waitsThe caller hands off to Lambda’s queueLambda’s own pollers
ExamplesAPI Gateway, ALB, function URL, Cognito, SDKS3, SNS, EventBridge, CloudWatch LogsSQS, Kinesis, DynamoDB Streams, MSK, MQ
RetriesCaller’s jobLambda: 2 by default, up to 6 hours ageUntil success, expiry or the source’s limit
Failed events go toThe caller (error response)On-failure destination or function DLQSQS: queue’s DLQ. Streams: on-failure destination
Payload6 MB request and response1 MBBatches (up to 6 MB total)

#Permissions: two policies, two directions

Lambda security has two sides, and mixing them up is a classic exam trap.

  • Execution role (outbound: what the function may call). An IAM role trusted by lambda.amazonaws.com. Lambda assumes it for every invocation and gives the temporary credentials to your code; the SDK finds them on its own. Writing logs needs the managed policy AWSLambdaBasicExecutionRole; add statements for S3, DynamoDB and the rest. Event source mappings also use this role to read the queue or stream.
  • Resource-based policy (inbound: who may invoke the function). A policy on the function itself. AWS services that push events (S3, SNS, EventBridge, API Gateway, CloudWatch Logs) and other accounts need a statement here allowing lambda:InvokeFunction. The console adds it when you add a trigger; the CLI command is aws lambda add-permission. Limit service principals with a source ARN and source account.

Who may call the function, and what may it call?

The thumbnail function of the Dhaka shop. Inbound permission (who may invoke it) lives in the function’s resource-based policy; outbound permission (what the code may touch) lives in its execution role.

Scenario

What the code may call: assumed by Lambda, used by the SDK.

S3 uploads
Browser
Partner account
thumbnail-exampleexecution role
CloudWatch Logs
DynamoDB table
Thumbnails bucket

Execution role: thumbnail-role

AllowOn
logs:CreateLogStream, logs:PutLogEvents/aws/lambda/thumbnail-example
s3:GetObjectuploads-example/*
s3:PutObjectthumbs-example/*
dynamodb:PutItemtable/photos
Step 1 of 3
1

Every function has exactly one execution role, an IAM role that trusts lambda.amazonaws.com. Lambda assumes it and hands its temporary credentials to your code through environment variables; the AWS SDK picks them up. No access keys in code, ever.

The execution role’s trust policy is always the same:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "lambda.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }]
}

Across accounts, both sides must allow, as in lesson 2.2: the caller’s identity policy and the function’s resource-based policy. Inside one account, either one is enough for an IAM user or role.

#Function URLs

A function URL is a dedicated HTTPS endpoint for one function, https://<url-id>.lambda-url.<region>.on.aws, invoked synchronously. It is free (you pay only for the invocations), supports CORS settings and response streaming, and suits webhooks (a payment gateway calling you back), a single-function microservice or a quick internal tool.

  • AuthType AWS_IAM: callers must sign requests with SigV4 and be allowed lambda:InvokeFunctionUrl, plus lambda:InvokeFunction for URLs created since October 2025.
  • AuthType NONE: public; the resource-based policy must still allow public invocation (the console adds it). Your code checks any token itself.

A function URL has no API keys, usage plans, request validation, caching or WAF of its own. For those, use API Gateway (lesson 15.6), or put CloudFront in front of the URL (CloudFront can sign its requests to the URL with origin access control, so only CloudFront can call it).

#Versions and aliases

While you develop, you edit $LATEST. Publishing creates a numbered version (1, 2, 3…): an immutable snapshot of code and configuration with its own ARN (…:function:checkout:7). An alias is a named pointer to a version (…:function:checkout:live) that you can move. Triggers, API Gateway and event source mappings should point at an alias, so a release or a rollback is just moving the alias.

An alias can also split traffic between two versions by weight (90% to version 7, 10% to version 8): a canary. AWS CodeDeploy automates this (canary, linear or all-at-once shifting, rollback on CloudWatch alarms), and AWS SAM sets it up with a few lines. Provisioned concurrency (lesson 15.2) is also configured on an alias or a version, never on $LATEST.

Versions, aliases and a safe rollout

API Gateway calls the checkout function through the alias “live”, never through a number. Publishing creates frozen versions; moving the alias changes what runs.

Scenario

$LATEST is editable; a published version is frozen.

API Gateway
Alias “live”
Version 7
Step 1 of 2
1

You always edit $LATEST. Publishing takes a snapshot of its code and configuration as version 7, with its own ARN ending in :7. A version can never be changed again, so “version 7” always means the same code.

#Two classic examples

The slides end the Lambda introduction with two small architectures. Both appear in exam questions in many disguises.

1. Thumbnails on upload. An S3 event notification (s3:ObjectCreated:*, filtered to .jpg) invokes the function asynchronously. The function downloads the image, writes a thumbnail to another bucket and the metadata (name, size, creation date, thumbnail key) to a DynamoDB table. No server waits for uploads; the shop pays a few hundred milliseconds per photo.

2. A serverless cron job. An EventBridge schedule (the slides still call it CloudWatch Events) invokes the function every hour, or with a cron expression, to run a task. Today AWS recommends EventBridge Scheduler for new schedules: one-time or recurring, with time zones and flexible windows, and millions of schedules per account.

Two classic Lambda jobs: thumbnails and a cron

A product photo uploaded to S3 becomes a thumbnail plus a metadata item in DynamoDB; an EventBridge schedule runs a report every night. Both run with no server, and both have classic ways to go wrong.

Scenario

S3 event → Lambda → thumbnail bucket + DynamoDB item.

uploads-example
Lambda function
thumbs-example
photos table
ObjectCreated

S3 event (shortened)

eventName

ObjectCreated:Put

bucket

uploads-example

key

products/saree-042.jpg

size

4,194,304

Step 1 of 3
1

A seller uploads saree-042.jpg (4 MB) to uploads-example. The bucket’s event notification for s3:ObjectCreated:* with the suffix .jpg invokes the function asynchronously (lesson 10.7).

#How Lambda is priced

You pay for two things, plus extras only if you use them:

  1. Requests: 0.20 USD per million invocations (0.0000002 USD each).
  2. Duration × memory, measured in GB-seconds: the configured memory in GB times the run time in seconds, rounded up to the millisecond. In US East (N. Virginia): 0.0000166667 USD per GB-second on x86 and 0.0000133334 USD on Arm (Graviton), 20% less. Cheaper tiers start above 6 billion GB-seconds a month on x86 and 7.5 billion on Arm. Since August 2025 the init phase of a cold start is billed as duration too.

The free tier, every month, per account and shared by all functions: 1 million requests and 400,000 GB-seconds. 400,000 GB-seconds is 400,000 seconds at 1 GB, 3,200,000 seconds at 128 MB (0.125 GB), or 800,000 seconds at 512 MB.

Extras: ephemeral storage above the free 512 MB, provisioned concurrency (lesson 15.2), data transfer out, and CloudWatch Logs ingestion (often bigger than the Lambda bill for chatty functions). Compute Savings Plans (lesson 4.4) also cover Lambda duration.

#A worked example

The thumbnail function: 3 million invocations a month, 512 MB, 800 ms on average, x86, free tier available.

  1. Compute: 3,000,000 × 0.5 GB × 0.8 s = 1,200,000 GB-seconds. Minus the free 400,000 = 800,000 billed. 800,000 × 0.0000166667 = 13.33 USD.
  2. Requests: 3,000,000 − 1,000,000 free = 2,000,000 × 0.20 USD per million = 0.40 USD.
  3. Total: 13.73 USD a month. On Arm: 800,000 × 0.0000133334 = 10.67, plus 0.40 = 11.07 USD.

A t3.small running all month costs 0.0208 × 730 = 15.18 USD, before its EBS volume, and it would be idle most of the night and overwhelmed during a sale. Now try 50 million invocations: Lambda passes 200 USD a month, while a few instances would do the same work for less. Lambda wins for spiky and low-to-medium traffic; steady, heavy load favours servers.

What does a Lambda function cost per month?

The Dhaka shop’s thumbnail function, or any other. Choose the memory, how long one invocation runs on average, how many invocations a month, the architecture, whether the free tier still applies, and an EC2 instance that would do the same work all month. Then calculate.

Memory

Average duration

Invocations per month

Architecture

Free tier

Compare with EC2 (always on)

Press “Calculate” to see the result.

#What goes wrong

SymptomLikely causeFix
Task timed out after 900.00 secondsThe job needs more than 15 minutesSplit the work (SQS, Step Functions Map), or use Fargate / AWS Batch
Task timed out after 3.00 secondsThe default timeout is 3 secondsRaise the timeout to what the work needs, and check slow downstream calls
AccessDeniedException inside the functionThe execution role lacks the actionAdd the permission to the execution role, not the code
S3 refuses to save the notification, or the trigger never firesNo resource-based policy statement for s3.amazonaws.comaws lambda add-permission with source ARN and account
Synchronous callers get 429No concurrency left in the Region or for the functionReserved concurrency, quota increase, or a queue in between (lesson 15.2)
Failed S3 events disappearAsynchronous invocation with no destination or DLQAdd an on-failure destination and alarm on it
The same SQS message is processed again and againThe function fails or runs longer than the visibility timeoutFix the error, raise the visibility timeout, add a redrive DLQ, use partial batch responses
A Kinesis shard stops movingA poison record fails the batch foreverBisect batch on error, maximum retries, on-failure destination
Invocations and cost explode after a deployThe function writes to the bucket or queue that triggers itSeparate output bucket or prefix; recursive loop detection as a safety net
OutOfMemory / Runtime exitedMemory too small for the dataRaise memory (also gives more CPU)
The first request after a quiet period is slowCold startLighter package and init code, provisioned concurrency or SnapStart (lesson 15.2)

#Lambda in system design

Use Lambda as the glue and the event handler of an architecture: an API backend with spiky traffic, processing files as they land in S3, consuming queues and streams, scheduled jobs, reacting to AWS events (an EC2 state change, a GuardDuty finding), and small automation tasks. Its strengths are zero idle cost, scaling in seconds and no operations.

Watch the boundaries: 15 minutes per invocation, 1,000 concurrent executions per Region by default, 6 MB synchronous payloads, a cold start on new environments, and no access to private VPC resources unless you attach the function to a VPC (lesson 15.3). The chapter-14 chooser pointed short, event-driven tasks to Lambda and long-running containers to Fargate; lesson 15.8 puts Lambda, Fargate and EC2 side by side for whole architectures.

#Try it yourself

These commands create the thumbnail function in ap-southeast-1 with the CLI. Use a sandbox account; everything stays within the free tier.

REGION=ap-southeast-1
ACCOUNT=111122223333

# 1. Execution role trusted by Lambda, with the logs policy
aws iam create-role --role-name thumbnail-role \
  --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow",
  "Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
aws iam attach-role-policy --role-name thumbnail-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

# 2. Create the function from app.py zipped as function.zip (arm64 is 20% cheaper)
zip function.zip app.py
aws lambda create-function --function-name thumbnail-example \
  --runtime python3.13 --architectures arm64 --handler app.handler \
  --role arn:aws:iam::$ACCOUNT:role/thumbnail-role \
  --memory-size 512 --timeout 30 --zip-file fileb://function.zip \
  --environment "Variables={TABLE_NAME=photos}" --region $REGION
# { "FunctionName": "thumbnail-example", "State": "Pending", "Runtime": "python3.13", ... }

# 3. Invoke synchronously and read the result
aws lambda invoke --function-name thumbnail-example --cli-binary-format raw-in-base64-out \
  --payload '{"Records":[{"s3":{"object":{"key":"products/saree-042.jpg"}}}]}' out.json
# { "StatusCode": 200, "ExecutedVersion": "$LATEST" }
cat out.json
# {"status": "ok", "key": "products/saree-042.jpg"}

# 4. Invoke asynchronously: Lambda only says it accepted the event
aws lambda invoke --function-name thumbnail-example --invocation-type Event \
  --cli-binary-format raw-in-base64-out --payload '{"Records":[]}' out.json
# { "StatusCode": 202 }

# 5. Asynchronous settings: 1 retry, 1 hour max age, failures to an SQS queue
aws lambda put-function-event-invoke-config --function-name thumbnail-example \
  --maximum-retry-attempts 1 --maximum-event-age-in-seconds 3600 \
  --destination-config '{"OnFailure":{"Destination":"arn:aws:sqs:ap-southeast-1:111122223333:thumb-failures-example"}}'

# 6. Allow the uploads bucket to invoke the function (resource-based policy)
aws lambda add-permission --function-name thumbnail-example --statement-id s3-uploads \
  --action lambda:InvokeFunction --principal s3.amazonaws.com \
  --source-arn arn:aws:s3:::uploads-example --source-account $ACCOUNT
aws lambda get-policy --function-name thumbnail-example --query Policy --output text

# 7. Publish version 1 and point the alias "live" at it
aws lambda publish-version --function-name thumbnail-example
# { "Version": "1", "FunctionArn": "arn:aws:lambda:ap-southeast-1:111122223333:function:thumbnail-example:1", ... }
aws lambda create-alias --function-name thumbnail-example --name live --function-version 1
# Later: send 10% of traffic to version 2
aws lambda update-alias --function-name thumbnail-example --name live --function-version 1 \
  --routing-config '{"AdditionalVersionWeights":{"2":0.1}}'

# 8. A function URL with IAM authentication
aws lambda create-function-url-config --function-name thumbnail-example --auth-type AWS_IAM
# { "FunctionUrl": "https://abcdefghijklmnopqrstuvwxyz123456.lambda-url.ap-southeast-1.on.aws/", "AuthType": "AWS_IAM" }

# 9. A serverless cron: every day at 6 a.m. Dhaka time with EventBridge Scheduler
aws scheduler create-schedule --name nightly-report-example \
  --schedule-expression "cron(0 6 * * ? *)" --schedule-expression-timezone Asia/Dhaka \
  --flexible-time-window Mode=OFF \
  --target '{"Arn":"arn:aws:lambda:ap-southeast-1:111122223333:function:report-example",
             "RoleArn":"arn:aws:iam::111122223333:role/scheduler-invoke-example"}'

# 10. Watch the logs, then clean up
aws logs tail /aws/lambda/thumbnail-example --follow
aws lambda delete-function --function-name thumbnail-example

Run step 3 twice and compare the Init Duration line in the log: it appears only on the cold start. Then raise the memory to 1,769 MB with aws lambda update-function-configuration and watch Duration fall for CPU-heavy code. EventBridge Scheduler uses its own IAM role (RoleArn) to invoke the function, so it needs no resource-based policy statement.

#Summary

Key takeaways

  • Serverless = no servers to manage, pay per use, automatic scaling down to zero. It started as FaaS with AWS Lambda and now covers DynamoDB, API Gateway, S3, SNS/SQS, Data Firehose, Aurora Serverless, Step Functions, Fargate, Cognito and EventBridge.
  • EC2 runs continuously, is limited by CPU and RAM, and scales by adding instances in minutes. Lambda runs per event, is limited by time (15 minutes), scales per request in seconds (1,000 concurrent executions per Region by default), and bills per request and per millisecond.
  • Memory 128 MB to 10,240 MB; CPU grows with memory (1,769 MB = 1 vCPU). Logs and metrics go to CloudWatch automatically.
  • Runtimes (October 2026): Node.js 22/24, Python 3.11–3.14, Java 8–25, .NET 8/10 (C#, PowerShell), Ruby 3.3–4.0, and the OS-only provided.al2023 for Go, Rust and others. Go 1.x and Amazon Linux 2 runtimes are retired or ending. Container images up to 10 GB must implement the Lambda Runtime API; arbitrary images belong on ECS/Fargate.
  • Synchronous (API Gateway, ALB, function URL, Cognito): caller waits, caller retries, 6 MB. Asynchronous (S3, SNS, EventBridge): 202, Lambda retries twice, 1 MB, then an on-failure destination or DLQ. Event source mapping (SQS, Kinesis, DynamoDB Streams): Lambda polls and sends batches; SQS failures go to the queue’s DLQ.
  • Execution role = what the function may call. Resource-based policy = who may invoke it (S3, SNS, EventBridge, API Gateway, other accounts). Function URL = built-in HTTPS endpoint, AWS_IAM or NONE.
  • Versions are immutable snapshots; aliases point to them and can split traffic for canaries and instant rollbacks.
  • Classic patterns: S3 upload → Lambda → thumbnail in another bucket + metadata in DynamoDB; EventBridge schedule → Lambda as a serverless cron.
  • Price = 0.20 USD per million requests + GB-seconds (x86 0.0000166667, Arm 20% less), rounded to 1 ms; free tier 1 million requests + 400,000 GB-seconds a month. Cheap for spiky work; steady heavy load is cheaper on servers.