AWS SAM Template Example
Deploy an AWS SAM template.yaml with Terraform — no migration, no rewrite
What you'll build
The same HTTP API as the Basic Service example,
but driven by an AWS SAM template.yaml instead of a serverless.yml.
sls.tf reads the SAM template directly, so the only change is
config_format = "sam" — everything else (Lambda, IAM, API Gateway, DynamoDB)
is provisioned the same way.
Project structure
my-api/
src/
list.js
create.js
template.yaml # AWS SAM template
main.tf
outputs.tf template.yaml
A standard SAM template. Globals, Parameters, and CloudFormation
intrinsics such as !Ref and !Sub are resolved at plan time.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Items API (SAM)
Parameters:
Stage:
Type: String
Default: dev
Globals:
Function:
Runtime: nodejs20.x
MemorySize: 256
Timeout: 10
Environment:
Variables:
TABLE_NAME: !Sub "items-${Stage}"
Resources:
ListItems:
Type: AWS::Serverless::Function
Properties:
Handler: src/list.handler
Description: List all items
Events:
ListApi:
Type: Api
Properties:
Path: /items
Method: get
CreateItem:
Type: AWS::Serverless::Function
Properties:
Handler: src/create.handler
Description: Create a new item
Events:
CreateApi:
Type: Api
Properties:
Path: /items
Method: post
ItemsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub "items-${Stage}"
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH main.tf
Point the module at template.yaml and set
config_format = "sam". Override template Parameters from Terraform
with sam_template_parameters:
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
module "serverless" {
source = "git::https://github.com/sls-tf/sls.tf.git?ref=v0.3.16"
config_path = "${path.module}/template.yaml"
config_format = "sam"
# Override the template's Parameters Default values
sam_template_parameters = {
Stage = "prod"
}
} outputs.tf
Outputs are identical regardless of config format — SAM logical IDs become the function keys:
output "api_url" {
description = "Base URL for the deployed API"
value = module.serverless.api_gateway_invoke_url
}
output "list_items_arn" {
value = module.serverless.function_arns["ListItems"]
}
output "create_item_arn" {
value = module.serverless.function_arns["CreateItem"]
}
output "table_name" {
value = module.serverless.custom_dynamodb_table_names["ItemsTable"]
} Deploy
terraform init
terraform plan
terraform apply
# Output example:
# api_url = "https://abc123.execute-api.us-east-1.amazonaws.com/prod" SAM-specific behaviour
Globals.Functiondefaults are merged into every function!Ref,!Sub,!GetAtt, and other intrinsics resolve at plan timeParametersuse theirDefaultunless overridden bysam_template_parameters- Function keys are the SAM logical IDs (
ListItems,CreateItem) Policieson a function become statements on its generated IAM role
Next steps
- Basic Service Example — the same API as a serverless.yml
- Resource Types — SAM resources sls.tf understands
- Configuration Guide —
sam_template_parametersand more