Skip to content

Serverless Framework in a few lines

A Serverless Framework functions: entry is short because the framework writes the rest. This is the usual example, a Python function that runs on a schedule:

functions:
  worker:
    handler: handler.cleanup
    runtime: python3.12
    memorySize: 512
    timeout: 600
    events:
      - schedule: cron(0 3 * * ? *)

The framework expands it into a CloudFormation template of about 120 lines. You never see that template unless you run sls package. The same function as patterns, from examples/serverless.py:

import cfn_typed as cfn
from cfn_types import lambda_
from cfn_typed_sumo.constructs import function, schedule


def build() -> cfn.Template:
    worker = function(
        "Worker",
        code=lambda_.FunctionCode(S3Bucket="deploy-artifacts", S3Key="my-service/package.zip"),
        handler="handler.cleanup",
        runtime="python3.12",
        memory=512,
        timeout=600,
    )
    return {
        "AWSTemplateFormatVersion": "2010-09-09",
        "Resources": cfn.combine(worker, schedule("Worker", "cron(0 3 * * ? *)", worker.function)),
    }

It renders to the template below, committed as serverless.yaml and checked by the test suite:

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  WorkerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
  WorkerLogs:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 30
  Worker:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: deploy-artifacts
        S3Key: my-service/package.zip
      Handler: handler.cleanup
      Runtime: python3.12
      MemorySize: 512
      Timeout: 600
      Role: !GetAtt WorkerRole.Arn
      LoggingConfig:
        LogGroup: !Ref WorkerLogs
  WorkerRule:
    Type: AWS::Events::Rule
    Properties:
      ScheduleExpression: cron(0 3 * * ? *)
      State: ENABLED
      Targets:
        - Id: Target0
          Arn: !GetAtt Worker.Arn
  WorkerPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref Worker
      Principal: events.amazonaws.com
      SourceArn: !GetAtt WorkerRule.Arn

What is the same, and what is not

The call is longer than the YAML, and the output is shorter than the framework's. Both differences are about where the work is done.

Serverless Framework Patterns
Function, role, log group generated function creates WorkerRole, WorkerLogs and Worker
Schedule and invoke permission generated schedule creates WorkerRule and WorkerPermission
Log group retention none by default 30 days, an argument
Code packaging and upload built in not done: Code points at an object you uploaded
Deployment bucket and its policy generated not done
A new Lambda version per deploy generated not done; see live_alias in CDK L2 constructs
Where you see the output sls package in the call, in the committed YAML
A misspelled MemorySize caught when you deploy caught by ty before you run anything

The patterns produce 47 lines because they leave out the packaging half of the framework. If you only want the CloudFormation side, that is the part you need: upload the zip with aws s3 cp or your CI, and pass the key. If you want the framework to package and upload for you, a pattern is not a replacement.

The IAM role is also narrower. The framework's role gets the permissions you list under iamRoleStatements, and here they are the statements argument of function, taking the same statements as grants:

function("Worker", ..., statements=grants.Sqs.Queue.consume_messages.on(orders.queue_arn))

Moving an existing service

To move a running service without replacing anything, see Ejecting from the Serverless Framework: it imports the template sls package writes and keeps its logical IDs. What follows is the manual way.

Capture what the framework generates and compare it with what the code renders:

  1. sls package, then take .serverless/cloudformation-template-update-stack.json.
  2. Build the same resources with the patterns and render them.
  3. Create a change set without executing it: aws cloudformation deploy --no-execute-changeset, then aws cloudformation describe-change-set.

A resource whose logical ID changes is a replacement, so the names matter. The framework derives them (WorkerLambdaFunction, WorkerLogGroup), while a pattern derives them from name. Name the pattern calls so the IDs match, or accept the replacement for stateless resources.