Skip to main content

Serverless workloads

Serverless removes the server from the delivery problem and replaces it with different problems: cold starts, concurrency limits, idempotency, and a cost model that punishes a badly designed loop.

Service map​

LayerServicesUse
ComputeLambdaStateless functions triggered by events
APIAPI Gateway (REST, HTTP, WebSocket)Exposure, throttling, authorisation
StorageS3, DynamoDBUnstructured data, key-value at scale
MessagingSQS, SNS, EventBridgeDecoupling, fan-out, routing
OrchestrationStep FunctionsMulti-step workflows, retries, human approval
StreamingKinesis, MSKReal-time event processing
RelationalAurora Serverless, RDS ProxySQL compatibility without connection exhaustion

Reference architecture​

Client
│
▼
API Gateway (WAF, throttling, auth)
│
▼
Lambda (stateless handler)
├──► DynamoDB (single-table design)
├──► S3 (objects)
└──► EventBridge ──► SQS ──► Lambda (async consumer)
│
└──► DLQ + alarm

Template​

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Globals:
Function:
Runtime: nodejs22.x
Architectures: [arm64]
Tracing: Active
LoggingConfig:
LogFormat: JSON
Environment:
Variables:
POWERTOOLS_SERVICE_NAME: example-service

Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/handlers/api.handler
MemorySize: 512
Timeout: 10
ReservedConcurrentExecutions: 50
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref Table
Events:
Api:
Type: HttpApi
Properties:
Path: /items
Method: post

AsyncFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/handlers/async.handler
MemorySize: 1024
Timeout: 60
Events:
Queue:
Type: SQS
Properties:
Queue: !GetAtt Queue.Arn
BatchSize: 10
FunctionResponseTypes: [ReportBatchItemFailures]

Queue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 360
RedrivePolicy:
deadLetterTargetArn: !GetAtt DLQ.Arn
maxReceiveCount: 3

DLQ:
Type: AWS::SQS::Queue
Properties:
MessageRetentionPeriod: 1209600

DLQAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: Messages have reached the dead-letter queue
MetricName: ApproximateNumberOfMessagesVisible
Namespace: AWS/SQS
Dimensions:
- Name: QueueName
Value: !GetAtt DLQ.QueueName
Statistic: Maximum
Period: 300
EvaluationPeriods: 1
Threshold: 1
ComparisonOperator: GreaterThanOrEqualToThreshold

Design rules​

Idempotency​

Every write path is idempotent. Lambda retries asynchronous invocations twice by default, and API Gateway can retry; a non-idempotent handler turns a transient failure into duplicate data.

  • Use a client-supplied idempotency key stored with a conditional write.
  • Make handlers safe to re-run: upsert rather than insert, or check-then-write under a condition.
  • For SQS batch consumers, report partial batch failures so only failed messages are retried.

Concurrency​

ControlPurpose
Reserved concurrencyGuarantees capacity for a critical function and caps its blast radius
Provisioned concurrencyRemoves cold starts for latency-sensitive paths
Account concurrency limitMonitored; a runaway function can exhaust the region's pool

A function with no reserved concurrency shares the account pool. One misbehaving consumer can starve every other function in the account.

Timeouts​

Set the function timeout below the upstream timeout. If API Gateway waits 29 seconds, the function must not run for 30. For queues, the visibility timeout must exceed the function timeout, or a message is redelivered while still being processed.

Cold starts​

  • Keep deployment packages small; tree-shake dependencies.
  • Prefer arm64 for price-performance.
  • Initialise SDK clients outside the handler.
  • Use provisioned concurrency only where a measured latency target requires it — it changes the cost model.

Dead letters​

Every asynchronous path has a dead-letter queue and an alarm on it. A queue without an alarm is a silent data loss mechanism.

Security​

  • Least-privilege execution role per function.
  • No * on action and resource in the same statement.
  • Environment variables for configuration; Secrets Manager or SSM for secrets, with the extension caching values rather than calling on every invocation.
  • VPC-attached functions only where they must reach private resources; otherwise they use the public AWS service endpoints with no NAT cost.
  • API Gateway authoriser on every non-public route; WAF on public endpoints.
  • Dependency scanning and signed deployments in the pipeline.

Observability​

  • Structured JSON logs with a correlation id and the request id.
  • X-Ray or OpenTelemetry tracing enabled.
  • Metrics per function: invocations, errors, duration, throttles, concurrent executions, cold-start count.
  • Alarms on error rate, throttle rate, p99 duration, DLQ depth, and age of the oldest message.

Cost​

Serverless cost is a function of invocations × duration × memory, plus the per-request charges of the surrounding services.

LeverEffect
Right-size memoryLambda CPU scales with memory; doubling memory can halve duration
Reduce invocation countBatch, aggregate, or move work to a queue consumer
Avoid pollingEvent-driven triggers instead of scheduled polls
Shorten durationMove slow I/O out of the request path
Set retentionCloudWatch Logs retention is a common hidden cost
Avoid idle provisioned concurrencyProvisioned capacity is billed even when unused