Quick Links

While Lambda has a web-based editor for updating your functions, it's intended for beginners, and isn't what you should use in practice. Creating functions with SAM templates allows you to move your Lambda functions onto your existing source control and CI/CD pipeline.

The Problem

If you're learning AWS and Lambda, you've probably seen this interface:

Lambda editor

This is Lambda's web editor, which allows you to edit the function directly from the page for that function. It's great for beginners, and can even be used extensively for small projects when extended with the Cloud9 IDE, which allows for local and remote debugging.

However, this isn't the real way you should be writing Lambda functions, especially if you're managing an entire microservices backend running on hundreds of them.

The solution is AWS's Serverless Application Model, or SAM for short. AWS characterizes SAM as a squirrel, for some reason:

SAM squirell

In reality though, SAM is a YAML template. Within the template, you define your application, and all the resources it needs (such as individual Lambda functions). Rather than updating your functions manually, you can deploy updates through SAM, which will handle it for you and update all of your functions at once.

SAM is an extension of AWS CloudFormation. They share most of the same syntax, but SAM is streamlined and specifically designed for Lambda. Whenever a new change is made and deployed, SAM updates the CloudFormation stack that it created when you initially deployed your template.

Because SAM is just a YAML file, it can be tracked and version controlled alongside all of your functions. This allows you to incorporate it into a CI/CD pipeline to automate build and deployment straight from Git. With everything set up, you could store your Lambda functions in a Git repository, and whenever you push new commits, CodePipeline will take the new changes and automatically run a SAM deployment to create a new Lambda version. It's even capable of slowing moving traffic between versions using alias traffic balancing, which can help you catch errors before they become problems.

If you'd like to learn more about using SAM in a CI/CD pipeline to automate Lambda deployments, you can read our guide on it here. For now though, we'll be focusing on using SAM itself, and running manual deployments from the CLI.

How to Write a SAM File

A typical SAM file will follow this basic format:

AWSTemplateFormatVersion: '2010-09-09'
    

Transform: AWS::Serverless-2016-10-31

Description: An AWS Serverless Specification template describing your function

Resources:

HelloWorld:

Type: AWS::Serverless::Function

Properties:

Handler: HelloWorld/index.handler

Runtime: nodejs8.10

This template simply defines a few config variables, and then, in the "Resources" section, defines Lambda functions by name. For example, here we're creating a function called "HelloWorld." this function runs on nodejs8.10, and its handler (starting point) is located in a subdirectory in an index.js file.

We can save this template as template.yml, and place it in a project directory alongside individual directories containing function code.

ProjectDirectory
    

|- template.yml

|- HelloWorld

|-index.js

This already presents a much easier way to manage Lambda functions. Multiple functions can be packed into one template, and all deployed at once.

However, Lambda isn't just code, and needs a lot more configuration to get working. Most notably, Lambda functions need an event to trigger off of. You can define this under the "Properties" section for a function. For example, to set the function to trigger off of an API Gateway

AWSTemplateFormatVersion: '2010-09-09'
    

Transform: AWS::Serverless-2016-10-31

Description: An AWS Serverless Specification template describing your function

Resources:

HelloWorld:

Type: AWS::Serverless::Function

Properties:

Handler: HelloWorld/index.handler

Runtime: nodejs8.10

Events:

HelloWorldApi:

Type: Api

Properties:

Path: /helloworld

Method: GET

When this is deployed, a new API Gateway for the Lambda project will be created automatically by SAM in CloudFormation, and linked to the newly created function on the paths specified.

SAM supports all of Lambda's other event source types. You can find more documentation for the other types on SAM's Github page.

SAM can also deploy more than just Lambda functions. Because it's a full extension of CloudFormation, you can deploy other resources that your application will need, all from SAM. For example, use Lambda with API Gateway, you'll need to grant API Gateway permission to invoke your function. You can do that with the following bit of code defining an AWS::Lambda::Permission resource:

AWSTemplateFormatVersion: '2010-09-09'
    

Transform: AWS::Serverless-2016-10-31

Description: An AWS Serverless Specification template describing your function

Resources:

HelloWorld:

Type: AWS::Serverless::Function

Properties:

Handler: HelloWorld/index.handler

Runtime: nodejs8.10

HelloWorldPermission:

Type: AWS::Lambda::Permission

Properties:

Action: lambda:InvokeFunction

FunctionName:

Fn::GetAtt:

- HelloWorld

- Arn

Principal: apigateway.amazonaws.com

SourceArn:

Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*/*/*

This is a little more complicated, but basically, it grants API Gateway permission to invoke the function in the FunctionName property. The Fn::GetAtt is an intrinsic function, which returns the ARN for the "HelloWorld" function, becaus you won't know what the exact ARN is going to be.

This is just scratching the surface of all that SAM can do. For more information on SAM template specification, you can consult the full schema on Github or read AWS's Developer Guides for using SAM.

Deploying a SAM File

In order for the SAM file to actually do anything, it will need to be deployed. This is handled automatically if you're using CodePipeline, but you can also trigger a deployment manually, which is better for beginners.

SAM has its own CLI, seperate from the standard AWS one. You can install it from pip:

pip install aws-sam-cli

First, you'll need to package everything, and send the artifacts to an S3 bucket:

sam package 
    

--template-file template.yml

--output-template-file package.yml

--s3-bucket bucket-name

Then, you can run the deployment, using the output template generated from the previous command:

sam deploy 
    

--template-file package.yml

--stack-name sam-hello-world

--capabilities CAPABILITY_IAM

Note that this command deploys a stack with a particular name defined by this command; there's nothing that sets the stack name in the SAM template itself. If you want to deploy a new stack, you can change this name here. Otherwise, keep the same name, and the stack will be updated instead.

When the SAM deployment completes, you'll see a new application with your functions, as well as a new stack in CloudFormation:

cloudformation stack