Skip to content

Patterns

Patterns are opinions

Everything in this section is a judgement about what is sensible, not a fact about CloudFormation, so it is kept apart from the generated types and the permission names. Treat the patterns as examples to copy and change, not as an API. See Facts first, opinions fenced.

A pattern is an ordinary function that returns a resource, or a small fragment of several resources. That is the whole idea. There is no base class, no registry and no construct tree.

def queue_with_dlq(name: str, *, visibility_timeout: int = 30) -> Resources: ...

A fragment is a Resources dict, a plain dict[str, AnyResource], so you combine fragments with | and drop the result into Template["Resources"].

A pattern can also return a handle: a small dataclass with a resources field plus the logical IDs and references callers need (orders.queue_arn). cfn.combine accepts a dict or any handle, via the HasResources protocol.

Conventions the patterns follow

  • Logical IDs are derived from a name argument and documented: queue_with_dlq("Order") creates OrderQueue and OrderDLQ. Callers then use the handle (orders.queue_arn) rather than retyping the IDs. The names are visible in the call, never generated behind your back.
  • A pattern that creates one resource returns that resource's type (iam.Role), and a pattern that creates several returns Resources, or a handle with a resources field when callers need to refer back to what it made.
  • Inputs are typed with Expr[T], so a caller can pass a literal or a Ref/GetAtt.
  • Optional pieces are only emitted when given. No Tags: [] noise in the output.

Your own patterns

The patterns in this book are examples and a starting point. The ones that pay off most are business specific, and only you can write them: your naming scheme, your mandatory tags and rules, how a service is wired to your platform. Write them as ordinary functions in your own repository (see a typical project), share them between repositories with Distributing patterns, and enforce the company's conventions with mandatory tags and company rules. Copy a pattern from here or from cfn-typed-sumo when it is close to what you need, and change it.

Where the code lives

The patterns in this book that live in a package ship as cfn-typed-sumo, a second package built from this repository that depends on cfn-typed. It is a fat pattern library with a volatile API, unlike the core (details):

uv add cfn-typed-sumo

The code is in packages/sumo/src/cfn_typed_sumo/patterns.py, type-checked and tested like any other code, and every snippet on these pages is pulled straight from that file. Import them (from cfn_typed_sumo import queue_with_dlq) or copy what you need and change it.

The package also ships the generated types its patterns use as a public module, cfn_typed_sumo.types. They are generated from packages/sumo/cfn-typegen.toml, which lists the resource types the patterns need plus the core and everyday services (IAM, Lambda, SQS, SNS, S3, KMS, DynamoDB, EC2, ECS, both API Gateways, CloudFront, RDS and so on, but not all of AWS); the repository does not contain them, and CI and the release build generate them. The snippets start from these imports:

import re
from collections.abc import Collection, Mapping, Sequence
from dataclasses import asdict, dataclass, fields
from typing import Any, Literal, TypedDict

from cfn_typed_sumo.types import iam, lambda_, sqs

from cfn_typed import AnyResource, AnyStatement, Expr, Resources, Tag, allow, arn, assume_role_policy, get_att, policy_document, ref
from cfn_typed.policy import service
from cfn_typed.checks import Rule
from cfn_typed.query import prop, resources_of
from cfn_typed.rules import each, forbid, require

Every pattern on these pages is in the package: the catalog lists them with links to the code and the resources each one creates. Only the stacks that assemble them stay in examples/.

Pattern Creates
Lambda execution role one AWS::IAM::Role
Queue with a dead-letter queue {name}Queue and {name}DLQ
SQS-triggered Lambda one AWS::Lambda::EventSourceMapping
Load balancer building blocks a load balancer, target group, listener or ingress rule
HTTP API with a JWT authorizer an HTTP API, a Lambda integration, a JWT authorizer, one route per route key and the invoke permission
One load balancer, several ports security group, load balancer, and a target group and listener per port
Encrypted storage a KMS key, a private bucket and its policy, a table, a repository
Publishing values through SSM SSM parameters that one stack publishes and another reads
Parameters as variables template parameters (including SSM), declared once and used as variables
CDK L2 constructs as patterns a Lambda function, a schedule, an SNS subscription, a VPC, a Fargate service, alarms, and auto scaling for services, Lambda aliases and tables
Web frontends a CloudFront static site, a REST API in front of a Lambda or a table, a Lambda behind a load balancer, DNS aliases
Messaging and events an SNS fan-out to queues with dead-letter queues, EventBridge rules to a Lambda or a queue
Data flows a table stream into a Lambda, a bucket that invokes a Lambda, Firehose into a bucket
Fargate tasks a cluster, a task and its two roles, for workers and for tasks a Lambda starts
Serverless Framework in a few lines the Serverless functions: example, a scheduled Lambda, as patterns
Mandatory tags nothing, but resolves and checks the tags a company requires, from service and per-resource values
Company rules nothing, but checks the finished template against rules of your own, as one more layer on the built-in checks
Composing fragments nothing, but how to combine the above safely
A complete stack all of the above in one template

Moving off SAM or the Serverless Framework, and uploading and releasing code, are in Deploying and migrating.