The AWS Serverless Application Model (SAM) transform is the magic that lets you write simpler, more readable CloudFormation templates for serverless applications.

Here’s SAM in action, defining a simple API Gateway endpoint backed by a Lambda function:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: A simple serverless API

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: hello-world-function
      Handler: app.lambda_handler
      Runtime: python3.9
      CodeUri: hello_world/
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get

Outputs:
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello"
  HelloWorldFunctionArn:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn

When you deploy this template using the SAM CLI or directly via CloudFormation, the AWS::Serverless-2016-10-31 transform kicks in before CloudFormation processes the template. It takes your simplified AWS::Serverless::Function, AWS::Serverless::Api, and other SAM resource types and expands them into their equivalent, more verbose CloudFormation resources. For instance, the AWS::Serverless::Function above gets translated into a full AWS::CloudFormation::Stack containing an AWS::Lambda::Function resource, an AWS::IAM::Role for permissions, and an AWS::APIGateway::RestApi, AWS::APIGateway::Resource, and AWS::APIGateway::Method if you defined API Gateway events. This abstraction is the core benefit: you focus on the serverless components, and SAM handles the underlying AWS infrastructure plumbing.

The primary problem SAM solves is the boilerplate and complexity inherent in writing direct CloudFormation for serverless architectures. Manually defining Lambda functions, their execution roles, API Gateway configurations, SQS queues, DynamoDB tables, and all the necessary permissions and interconnections quickly becomes unmanageable. SAM abstracts this away. A single AWS::Serverless::Function resource can encompass the Lambda function code, its runtime, handler, environment variables, triggers (like API Gateway, SQS, SNS), and necessary IAM permissions, all in a concise YAML block. The Transform directive is the mechanism that tells CloudFormation to delegate this expansion process to the SAM service.

The Transform directive is crucial. It’s not just a hint; it’s an instruction. When CloudFormation encounters Transform: AWS::Serverless-2016-10-31, it pauses its normal processing. It then invokes the SAM transformation service, passing your template. SAM’s service interprets the AWS::Serverless resources, generates the equivalent standard CloudFormation resources, and returns the expanded template back to CloudFormation for deployment. This means the template you deploy to CloudFormation is much more detailed than what you write in your SAM template file. You can even inspect this expanded template using sam build and sam deploy --guided (which implicitly builds) followed by aws cloudformation describe-stack-resources --stack-name <your-stack-name> to see the underlying CloudFormation resources SAM generated.

The mental model you should build is that SAM is a template preprocessor. You write SAM, and SAM transforms it into CloudFormation. This allows you to leverage the full power of CloudFormation (like intrinsic functions, stack policies, etc.) while benefiting from SAM’s simplified syntax for common serverless patterns. The Properties section of a SAM resource often directly maps to properties of the underlying CloudFormation resource, but with added convenience. For example, CodeUri in AWS::Serverless::Function is a SAM-specific property that tells SAM where to find your Lambda code. SAM then uses this to upload the code to S3 and configure the Code property of the underlying AWS::Lambda::Function resource.

What most people don’t realize is that the Transform directive can actually point to custom transforms you define yourself. While AWS::Serverless-2016-10-31 is the built-in SAM transform, you can create your own Lambda-backed custom resources that act as transforms. This allows you to define your own domain-specific language (DSL) for infrastructure-as-code, where your custom transform expands your simplified syntax into standard CloudFormation. This is a powerful, albeit advanced, feature that extends the abstraction capabilities far beyond what SAM offers out-of-the-box.

The next step is to explore how SAM’s sam build command works in conjunction with the transform to package your code and dependencies.

Want structured learning?

Take the full Cloudformation course →