skip to content

What does the line `Transform: AWS::Serverless-2016-10-31` at the top of a CloudFormation template do, and how does it change the way that template is deployed?

level: seniorimportance: nice to knowfreq 36%

answer

  1. a macro declared at the top
  2. shorthand expanded somewhere else
  3. the service rewrites, not your laptop
  4. an extra capability must be acknowledged
  5. the stack holds resources you never wrote

basics

~10 s

It declares the SAM macro, so CloudFormation expands the template's AWS::Serverless::* resources into plain resources on the service side before deploying. Deployments go through a change set and must pass the CAPABILITY_AUTO_EXPAND capability.

solid answer

~50 s

`Transform` names a macro that CloudFormation runs against your template server-side, and `AWS::Serverless-2016-10-31` is the Serverless Application Model macro. What you write is shorthand: an `AWS::Serverless::Function` expands into an `AWS::Lambda::Function`, a generated `AWS::IAM::Role`, event-source resources, and — if it declares an API event — an implicit REST API with its deployment and stage. Because the expansion happens on AWS's side, the processed template is not what you wrote, and two things follow. First, the deployment must be allowed to expand: you pass `CAPABILITY_AUTO_EXPAND` alongside the usual IAM capabilities, and you go through a change set, which is what `aws cloudformation deploy` and `sam deploy` do for you. Second, what you review in that change set is the *expanded* resource set, including resources you never named. `aws cloudformation get-template --template-stage Processed` shows you the expanded form.

code

yaml · 31 lines
yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
  Function:
    Runtime: python3.12
    Timeout: 10
Resources:
  Orders:
    Type: AWS::DynamoDB::Table
    Properties:
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH
  GetOrder:
    Type: AWS::Serverless::Function
    Properties:
      Handler: app.handler
      CodeUri: ./src
      Environment:
        Variables:
          TABLE_NAME: !Ref Orders
      Events:
        Http:
          Type: Api
          Properties:
            Path: /orders/{id}
            Method: get

go deeper

for a junior

Know that Transform declares a macro and that AWS::Serverless-2016-10-31 turns short serverless resource types into ordinary Lambda, IAM and API Gateway resources.

for a middle

Explain that expansion happens on the CloudFormation service side, name what a serverless function expands into, and say that deployment needs CAPABILITY_AUTO_EXPAND and goes through a change set.

for a senior

Draw out the review consequence — the change set shows generated resources, not your file — and know how to fetch the processed template and reason about implicit roles and APIs when troubleshooting.

for a principal

Own the call on when the shorthand stops paying: once most generated resources are being overridden, the abstraction costs review clarity, and plain templates or a construct-based tool become the better trade.

## Transform is a macro declaration `Transform` is a top-level template section whose value names one or more macros. A macro is a program that rewrites the template before CloudFormation provisions anything. AWS provides two well-known ones — `AWS::Serverless-2016-10-31`, the SAM transform, and `AWS::Include`, which splices in a snippet from S3 — and you can register your own macro backed by a Lambda function. The `Fn::Transform` intrinsic applies a macro to a fragment rather than the whole template. The crucial property is **where** the rewriting happens: on the CloudFormation service side, during change set creation, not on your laptop. The stack is created from the processed template, and the original is kept only for reference. ## What the SAM transform actually expands SAM adds resource types that are all shorthand: - `AWS::Serverless::Function` - `AWS::Serverless::Api` and `AWS::Serverless::HttpApi` - `AWS::Serverless::SimpleTable` - `AWS::Serverless::StateMachine` - `AWS::Serverless::LayerVersion` It also enables a `Globals` section, where you set defaults such as runtime, timeout and memory once for every function in the file — a section plain CloudFormation does not have. A single `AWS::Serverless::Function` with an API event typically becomes: an `AWS::Lambda::Function`; an `AWS::IAM::Role` for its execution role, named after the function's logical ID with `Role` appended; an `AWS::Lambda::Permission` allowing API Gateway to invoke it; and, if no explicit API was declared, an implicit REST API plus a deployment and a stage. Six-ish resources from a dozen lines. That is the value proposition, and it is also the thing to be conscious of when you read the stack's resource list and find names you never typed. ```yaml Transform: AWS::Serverless-2016-10-31 Resources: Hello: Type: AWS::Serverless::Function Properties: Handler: app.handler Runtime: python3.12 CodeUri: ./src ``` ## How deployment changes **You need `CAPABILITY_AUTO_EXPAND`.** CloudFormation treats macro expansion as a privileged act — a macro can introduce resources you did not write, including IAM ones — so you must explicitly acknowledge it. Deploying a SAM template therefore usually passes `--capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND`, or `CAPABILITY_NAMED_IAM` when a role carries an explicit name. **You go through a change set.** Expansion is part of change set creation, so the path to a stack runs create-change-set then execute-change-set. `aws cloudformation deploy` and `sam deploy` both do this under the hood, which is why the SAM documentation points you at them rather than at a direct create. **Local code has to be uploaded first.** `CodeUri: ./src` is a local path and CloudFormation cannot read your disk. `aws cloudformation package`, or `sam build` followed by `sam deploy`, zips the source, uploads it to an S3 bucket, and rewrites `CodeUri` to point at the uploaded object. Forgetting this step is the most common first-time SAM failure. ## The consequences worth naming in an interview **What you review is not what you wrote.** The change set lists expanded resources. If your review process is "read the diff of the template file", you are reviewing shorthand and deploying something larger. Pull the processed template with `aws cloudformation get-template --stack-name my-stack --template-stage Processed` when you need to know exactly what is in the stack. **Implicit resources are real resources.** The generated execution role, the implicit API and its stage all live in the stack, appear in its resource list, and are deleted with it. If you later want to control the role yourself, you set the function's `Role` property to an ARN and the generated one disappears — which is the removal of a real resource, not a cosmetic edit. **Validation moves later.** A malformed SAM property may not surface until the service expands it, so failures arrive at change set creation rather than at local lint time. `sam validate` catches some of it earlier. **You can always escape.** SAM resources are plain CloudFormation underneath, so a template can mix `AWS::Serverless::Function` with raw `AWS::SQS::Queue` and `AWS::DynamoDB::Table` freely, and `Ref` / `Fn::GetAtt` work across the boundary in the usual way. ## When the shorthand stops paying SAM is excellent when your stack really is a handful of functions, an API and a table. Once you are overriding most of what it generates — bringing your own role, your own API definition, your own stage settings — the shorthand has become indirection, and writing the underlying resources plainly is more honest. That judgment, rather than the syntax, is what a senior answer is being probed for.

  • Why does CloudFormation demand CAPABILITY_AUTO_EXPAND for a template with a Transform?
    Because a macro can inject resources you never wrote, including IAM roles and policies. The capability is you acknowledging that the deployed resource set is generated rather than fully visible in the file under review. It is the same reasoning as CAPABILITY_IAM, one level further out.
  • How do you see exactly which resources a SAM template produced?
    Two ways. Before deploying, create a change set and read its list of changes, which is expressed in expanded resources. After deploying, `aws cloudformation get-template --stack-name X --template-stage Processed` returns the expanded template, and the stack's resource list shows generated logical IDs such as the function's appended Role.
  • What happens if you deploy a SAM template whose CodeUri is a local directory without packaging it first?
    It fails — CloudFormation runs in the service, not on your machine, and cannot read a local path. `aws cloudformation package`, or `sam build` plus `sam deploy`, zips the source, uploads it to S3, and rewrites CodeUri to the uploaded object before the template is submitted.

saying these in an interview costs you the question

  • Believing the SAM CLI expands the template locally before upload
  • Deploying without CAPABILITY_AUTO_EXPAND and blaming the IAM capability
  • Assuming the stack contains only the resources written in the file
  • Thinking a SAM template cannot contain plain CloudFormation resources
  • Expecting a local CodeUri path to be readable by CloudFormation

context