SAM is a shorthand CloudFormation extension for serverless apps. It transforms simple SAM syntax into full CloudFormation templates. Think of it as CloudFormation but with much less boilerplate for Lambda, API Gateway, and DynamoDB.
Real-World: Defining a Lambda + API Gateway integration in raw CloudFormation takes ~200 lines. In SAM, it's ~15 lines. SAM generates the CloudFormation for you.
# CloudFormation: ~80 lines for a simple Lambda + API Gateway
# SAM equivalent: ~15 lines
Transform: AWS::Serverless-2016-10-31 # This line makes it SAM
Globals:
Function:
Timeout: 10
Runtime: python3.12
Environment:
Variables:
TABLE_NAME: !Ref OrdersTable
Resources:
OrdersFunction:
Type: AWS::Serverless::Function # SAM type
Properties:
Handler: handler.lambda_handler
CodeUri: src/orders/
Events:
GetOrders:
Type: Api
Properties:
Path: /orders
Method: GET
CreateOrder:
Type: Api
Properties:
Path: /orders
Method: POST
OrdersTable:
Type: AWS::Serverless::SimpleTable # SAM type → DynamoDB table
Properties:
PrimaryKey:
Name: orderId
Type: StringTransform: AWS::Serverless-2016-10-31 is the magic line that tells CloudFormation to process SAM syntax.
| SAM Type | What it creates |
|---|---|
AWS::Serverless::Function |
Lambda function + IAM role + event source mappings |
AWS::Serverless::Api |
API Gateway REST API + deployment + stage |
AWS::Serverless::HttpApi |
API Gateway HTTP API |
AWS::Serverless::SimpleTable |
DynamoDB table with single PK |
AWS::Serverless::Application |
Nested application (from SAR) |
AWS::Serverless::LayerVersion |
Lambda Layer |
AWS::Serverless::StateMachine |
Step Functions state machine |
OrdersFunction:
Type: AWS::Serverless::Function
Properties:
Events:
# API Gateway
RestApi:
Type: Api
Properties:
Path: /orders/{id}
Method: GET
# S3 trigger
S3Upload:
Type: S3
Properties:
Bucket: !Ref UploadBucket
Events: s3:ObjectCreated:*
Filter:
S3Key:
Rules:
- Name: suffix
Value: .jpg
# SQS trigger
OrderQueue:
Type: SQS
Properties:
Queue: !GetAtt OrderQueue.Arn
BatchSize: 10
FunctionResponseTypes:
- ReportBatchItemFailures
# DynamoDB Stream
StreamTrigger:
Type: DynamoDB
Properties:
Stream: !GetAtt OrdersTable.StreamArn
StartingPosition: LATEST
BatchSize: 100
# Schedule (cron)
DailyReport:
Type: Schedule
Properties:
Schedule: cron(0 8 * * ? *) # 8am UTC dailySAM CLI lets you run serverless apps locally before deploying.
# Invoke Lambda locally
sam local invoke OrdersFunction --event events/get-order.json
# Start local API Gateway
sam local start-api
# Now curl http://localhost:3000/orders
# Start local Lambda endpoint (for testing other services calling Lambda)
sam local start-lambda
# Generate a sample event payload
sam local generate-event apigateway aws-proxy --path /orders --method GET# Start DynamoDB local
docker run -p 8000:8000 amazon/dynamodb-local
# Use in your function - override endpoint in env vars
TABLE_ENDPOINT=http://localhost:8000 sam local invoke# Build (package Lambda code, resolve dependencies)
sam build
# Deploy (first time - interactive)
sam deploy --guided
# Deploy (subsequent times - uses samconfig.toml)
sam deploy
# Delete stack
sam delete[default.deploy.parameters]
stack_name = "my-app"
s3_bucket = "sam-artifacts-bucket"
s3_prefix = "my-app"
region = "us-east-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
parameter_overrides = "Environment=prod"For fast iterative development:
# Sync local changes to AWS without full deploy
sam sync --watch --stack-name my-app- Code changes: sync in seconds (bypass CloudFormation)
- Infrastructure changes: fall back to CloudFormation deploy
- Use for development only — not production
SAM provides shorthand IAM policies:
OrdersFunction:
Type: AWS::Serverless::Function
Properties:
Policies:
- DynamoDBCrudPolicy: # shorthand for CRUD on DynamoDB
TableName: !Ref OrdersTable
- S3ReadPolicy: # shorthand for S3 read
BucketName: !Ref DataBucket
- SQSSendMessagePolicy: # shorthand for SQS send
QueueName: !GetAtt NotificationQueue.QueueName
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn: !Ref DBSecretInstead of writing custom IAM JSON, use these pre-built policy templates.
Set defaults for all functions:
Globals:
Function:
Runtime: python3.12
Timeout: 30
MemorySize: 512
Tracing: Active # X-Ray for all functions
Layers:
- !Ref CommonLayer
Environment:
Variables:
LOG_LEVEL: INFO
TABLE_NAME: !Ref MainTable
Api:
Cors:
AllowOrigin: "'https://app.example.com'"
AllowHeaders: "'Authorization,Content-Type'"Override per function if needed.
Pre-built serverless apps you can deploy directly:
Resources:
# Use a pre-built app from SAR
SecretsRotationApp:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: arn:aws:serverlessrepo:us-east-1:297356227824:applications/SecretsManagerRDSMySQLRotationSingleUser
SemanticVersion: 1.1.60
Parameters:
functionName: rotate-db-secret
endpoint: !Sub 'https://secretsmanager.${AWS::Region}.amazonaws.com'| Practice | Reason |
|---|---|
| Use Globals to avoid repetition | DRY principle |
| Use SAM Policy Templates | Least privilege, readable |
| Test locally with SAM CLI before deploying | Fast feedback loop |
Use sam sync for dev, sam deploy for prod |
Speed in dev, safety in prod |
| Store samconfig.toml in version control | Reproducible deployments |
| Use nested SAM apps for microservices | Each service has its own SAM template |
- SAM is a superset of CloudFormation — any CloudFormation resource can be in a SAM template.
Transform: AWS::Serverless-2016-10-31— required for SAM. This is the transform that CloudFormation uses.- SAM CLI requires Docker for local Lambda invocation.
sam buildpackages dependencies.sam deploydeploys to AWS.- SAM Accelerate (
sam sync) is for fast local dev → not for production deployments. - SAM Policy Templates: shorthand for common IAM permissions (DynamoDBCrudPolicy, S3ReadPolicy, etc.)
Q: Quickly develop and test Lambda locally before deploying?
→ Use SAM CLI: sam local invoke / sam local start-api.
Q: Define Lambda + API Gateway + DynamoDB with minimal code?
→ SAM template with AWS::Serverless::Function, AWS::Serverless::Api, AWS::Serverless::SimpleTable.
Q: Deploy serverless app across multiple environments?
→ SAM with Parameters + sam deploy --parameter-overrides Environment=prod.