โšก Onwuachi Control Plane

Aws Cloudformation Parameters Mappings Functions

Overview

AWS CloudFormation templates become significantly more powerful when they can accept input, look up environment-specific values, and dynamically reference resources.

Three important CloudFormation features provide this capability:

Parameters
    |
    | Values provided at deployment time
    v
Mappings
    |
    | Static lookup tables
    v
Intrinsic Functions
    |
    | Dynamically reference and transform values
    v
Resources

The simple mental model is:

Parameters provide input. Mappings provide lookup data. Intrinsic functions connect everything together.

For example, the same CloudFormation template might be used to deploy an application into:

Instead of hardcoding every value directly into the template, CloudFormation can accept deployment-specific inputs and dynamically determine the correct configuration.

Why It Matters

A basic CloudFormation template can work well for a single environment:

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.micro

But real infrastructure usually needs to vary by environment.

For example:

Development
    |
    +--> t3.micro
    +--> Small database
    +--> Development VPC

Staging
    |
    +--> t3.small
    +--> Medium database
    +--> Staging VPC

Production
    |
    +--> t3.large
    +--> Large database
    +--> Production VPC

Hardcoding these values into separate templates creates duplication.

A better approach is to make the template reusable:

                   One Template
                        |
             +----------+----------+
             |          |          |
             v          v          v
          Dev        Staging      Prod
             |          |          |
             v          v          v
        Different    Different   Different
        Parameters   Parameters  Parameters
        / Lookups    / Lookups   / Lookups

This reduces template duplication and makes infrastructure easier to maintain.

The three features have different purposes:

FeaturePurpose
ParametersAccept values when a stack is created or updated
MappingsStore static key-value relationships inside the template
Intrinsic FunctionsDynamically reference, substitute, join, select, or transform values

Understanding the difference between these features is important both for practical CloudFormation work and AWS certification exams.


Where It Fits

Parameters, Mappings, and intrinsic functions sit between the deployment input and the resources CloudFormation creates.

A simplified workflow is:

Deployment Command
        |
        | Parameter values
        v
CloudFormation Template
        |
        +----------------------+
        |                      |
        v                      v
    Parameters             Mappings
        |                      |
        +----------+-----------+
                   |
                   v
          Intrinsic Functions
                   |
                   | Resolve values
                   v
              Resources
                   |
                   v
              AWS Services

For example:

aws cloudformation create-stack
        |
        | Environment=prod
        v
CloudFormation Parameters
        |
        v
Fn::FindInMap
        |
        | Find production value
        v
Instance Type
        |
        v
EC2 Instance

The template remains the same while the deployment inputs or lookup values determine the resulting infrastructure.


The Big Picture

CloudFormation templates commonly use these sections:

AWSTemplateFormatVersion
Description
Parameters
Mappings
Conditions
Resources
Outputs

For this article, the most important relationship is:

Parameters
    |
    | User-provided or deployment-provided input
    v
Resources
    ^
    |
Mappings
    |
    | Static lookup
    v
Intrinsic Functions

A more complete example:

Parameters:
  Environment:
    Type: String
    Default: dev

Mappings:
  EnvironmentMap:
    dev:
      InstanceType: t3.micro
    prod:
      InstanceType: t3.large

Resources:
  ApplicationInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !FindInMap
        - EnvironmentMap
        - !Ref Environment
        - InstanceType

The deployment flow is:

Parameter:
Environment = prod
        |
        v
Ref Environment
        |
        v
FindInMap
        |
        v
EnvironmentMap[prod][InstanceType]
        |
        v
t3.large
        |
        v
EC2 Instance

One template can now support multiple environments.


Core Concepts

Parameters

CloudFormation Parameters allow values to be supplied when a stack is created or updated.

A basic parameter looks like:

Parameters:
  Environment:
    Type: String
    Default: dev

The parameter can then be referenced elsewhere in the template.

For example:

Resources:
  ApplicationBucket:
    Type: AWS::S3::Bucket
    Tags:
      - Key: Environment
        Value: !Ref Environment

If the stack is deployed with Environment = production, the resulting resource receives Environment = production. The template does not need to be modified.

Parameter Types

CloudFormation supports several parameter types. Common examples include:

Parameters:
  Environment:
    Type: String

  InstanceCount:
    Type: Number

  EnableMonitoring:
    Type: String

  VpcId:
    Type: AWS::EC2::VPC::Id

  SubnetId:
    Type: AWS::EC2::Subnet::Id

Using AWS-specific parameter types can improve validation and user experience when parameters are supplied through the CloudFormation console or APIs. For example, Type: AWS::EC2::VPC::Id tells CloudFormation that the parameter should represent a VPC ID rather than arbitrary text.

Parameter Defaults

Parameters can have default values:

Parameters:
  Environment:
    Type: String
    Default: dev

If the user does not provide a value, CloudFormation uses the default. Defaults are useful for development environments, optional configuration, common deployment values, and simplifying testing.

Be careful with defaults for production resources โ€” a default that is convenient for development can be dangerous if it is accidentally used in production.

AllowedValues

Parameters can restrict acceptable values:

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - prod

This prevents invalid environment names from being supplied, constraining input to a known-good set instead of arbitrary strings like production, PROD, or Production. Constraining inputs reduces configuration mistakes.

AllowedPattern

String parameters can also be validated using regular expressions:

Parameters:
  Environment:
    Type: String
    AllowedPattern: '^[a-z]+$'

Parameter validation should be used where it improves safety, but overly restrictive patterns can make templates unnecessarily difficult to use.

MinLength and MaxLength

Parameters:
  ApplicationName:
    Type: String
    MinLength: 3
    MaxLength: 32

Useful when AWS resource naming requirements impose constraints.

NoEcho

Sensitive parameter values can use NoEcho:

Parameters:
  DatabasePassword:
    Type: String
    NoEcho: true

NoEcho prevents the parameter value from being displayed in certain CloudFormation interfaces. However:

NoEcho is not a replacement for a secrets-management service.

For production secrets, prefer AWS Secrets Manager, AWS Systems Manager Parameter Store, or dynamic references where appropriate. Avoid storing long-lived credentials directly in CloudFormation parameters when a managed secret solution is available.

Referencing Parameters with Ref

The Ref intrinsic function retrieves the value of a parameter:

Parameters:
  Environment:
    Type: String
    Default: dev

Resources:
  ApplicationBucket:
    Type: AWS::S3::Bucket
    Properties:
      Tags:
        - Key: Environment
          Value: !Ref Environment

If Environment = prod, then !Ref Environment resolves to prod. Ref is one of the most commonly used CloudFormation intrinsic functions.

Parameters Are Inputs, Not Environment Variables

CloudFormation parameters exist during stack deployment:

CloudFormation Deployment
        |
        v
Parameter
        |
        v
Resource Configuration

Application environment variables exist at runtime:

Application Startup
        |
        v
Environment Variable
        |
        v
Application Behavior

A CloudFormation parameter may be used to configure an environment variable, but the two concepts are not identical.


Mappings

Mappings provide static key-value lookup tables inside a CloudFormation template. They are useful when a template needs to select a value based on known keys.

Mappings:
  RegionMap:
    us-east-1:
      AMI: ami-11111111111111111
    us-west-2:
      AMI: ami-22222222222222222

Conceptually:

Region
   |
   v
us-east-1
   |
   v
RegionMap
   |
   v
AMI
   |
   v
ami-11111111111111111

Mappings are especially useful for static configuration that does not need to be supplied by the user during deployment.

Mappings vs. Parameters

Parameters โ€” values are provided at deployment time:

User / Pipeline
      |
      v
Parameter
      |
      v
CloudFormation

Mappings โ€” values are already defined in the template:

CloudFormation Template
      |
      v
Mapping
      |
      v
Lookup
FeatureParametersMappings
Value sourceDeployment inputTemplate-defined
User changes value?YesNo, unless template changes
Good forEnvironment selectionStatic lookup tables
ExampleEnvironment=prodprod -> t3.large
Main functionInputLookup

Fn::FindInMap

The Fn::FindInMap intrinsic function retrieves a value from a Mapping:

Mappings:
  EnvironmentMap:
    dev:
      InstanceType: t3.micro
    prod:
      InstanceType: t3.large
InstanceType: !FindInMap
  - EnvironmentMap
  - !Ref Environment
  - InstanceType

The lookup works like FindInMap(MapName, TopLevelKey, SecondLevelKey). With MapName = EnvironmentMap, TopLevelKey = prod, SecondLevelKey = InstanceType, the result is t3.large.

The combined pattern is powerful:

Parameter
    |
    v
Ref
    |
    v
Mapping Key
    |
    v
FindInMap
    |
    v
Environment-Specific Value

Intrinsic Functions

CloudFormation intrinsic functions allow templates to dynamically reference and manipulate values. Common functions include:

Ref
Fn::GetAtt
Fn::Sub
Fn::Join
Fn::Select
Fn::Split
Fn::FindInMap
Fn::ImportValue
Fn::If
Fn::Equals
Fn::And
Fn::Or
Fn::Not

Ref

Ref retrieves a parameter value or references a resource.

For a parameter: !Ref Environment returns the parameter value.

For a resource, Ref generally returns the resource’s primary identifier โ€” the exact return value depends on the resource type.

Fn::GetAtt

Fn::GetAtt retrieves an attribute from a resource:

Outputs:
  BucketArn:
    Value: !GetAtt ApplicationBucket.Arn

The difference between Ref and GetAtt is important:

Ref        โ†’  Primary resource reference
GetAtt     โ†’  Specific resource attribute

!Ref ApplicationBucket may return the bucket name, while !GetAtt ApplicationBucket.Arn returns the full ARN. The exact behavior depends on the resource type โ€” worth confirming in the docs rather than assuming.

Fn::Sub

Fn::Sub performs string substitution:

BucketName: !Sub "my-application-${Environment}"

If Environment = prod, the resulting name becomes my-application-prod. Fn::Sub is often easier to read than manually joining strings.

Fn::Join

Fn::Join combines values using a delimiter:

!Join
  - '-'
  - - my-application
    - prod
    - web

Result: my-application-prod-web. Fn::Sub is often preferred when constructing strings containing variables because it is generally easier to read.

Fn::Select

Fn::Select retrieves an item from a list by index:

!Select
  - 0
  - - subnet-a
    - subnet-b
    - subnet-c

Result: subnet-a (indexes are zero-based). Be careful โ€” CloudFormation does not validate whether the selected index contains a valid value.

Fn::Split

Fn::Split converts a delimited string into a list:

!Split
  - ','
  - subnet-a,subnet-b,subnet-c

Result: [subnet-a, subnet-b, subnet-c]. A common pattern is Split โ†’ Select to pull an individual value out of a comma-separated parameter.

Fn::ImportValue

Fn::ImportValue retrieves an exported value from another CloudFormation stack, allowing stacks to share infrastructure values:

Network Stack
    |
    | Exports VPC ID
    v
VPC ID
    |
    v
Application Stack
    |
    | Fn::ImportValue
    v
Application Resources

A network stack exports:

Outputs:
  VpcId:
    Value: !Ref VPC
    Export:
      Name: SharedVpcId

Another stack imports it:

VpcId: !ImportValue SharedVpcId

Be careful with exported values โ€” exports create dependencies between stacks (you can’t delete the exporting stack until all imports are removed).

Conditional Functions

CloudFormation also supports conditional logic: Fn::If, Fn::Equals, Fn::And, Fn::Or, Fn::Not.

Conditions:
  IsProduction: !Equals
    - !Ref Environment
    - prod
DeletionPolicy: !If
  - IsProduction
  - Retain
  - Delete

This allows a single template to behave differently based on deployment conditions.


Real-World Example

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - prod

Mappings:
  EnvironmentMap:
    dev:
      InstanceType: t3.micro
    staging:
      InstanceType: t3.small
    prod:
      InstanceType: t3.large

Resources:
  ApplicationInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !FindInMap
        - EnvironmentMap
        - !Ref Environment
        - InstanceType
      Tags:
        - Key: Name
          Value: !Sub "${Environment}-application"

With Environment = dev: dev โ†’ FindInMap โ†’ t3.micro. With Environment = prod: prod โ†’ FindInMap โ†’ t3.large. The same template supports both.

                   One CloudFormation Template
                              |
                 +------------+------------+
                 |            |            |
                 v            v            v
               dev         staging        prod
                 |            |            |
                 v            v            v
              t3.micro     t3.small     t3.large

Live worked example (from this KB’s hands-on lab)

This exact pattern was run live against a real devopslab stack:

Parameters:
  InstanceTypeParam:
    Type: String
    Default: t3.micro

Mappings:
  RegionMap:
    us-east-1:
      AMI: ami-0006118602dfc1c09

Resources:
  DemoInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceTypeParam
      ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AMI]

Outputs:
  InstanceId:
    Value: !Ref DemoInstance
  InstancePublicDNS:
    Value: !GetAtt DemoInstance.PublicDnsName

Deployed with InstanceTypeParam=t3.micro, the stack resolved:

This confirms the Ref vs. GetAtt distinction concretely: Ref on an EC2 instance returns the instance ID, not its DNS name โ€” GetAtt is required for anything beyond the ID. The stack was torn down immediately after (delete-stack), confirmed removed via a follow-up describe-stacks returning a “does not exist” validation error โ€” full lab cost: effectively $0, since the instance ran only a few minutes on a t3.micro.

The same pattern extends to AMI IDs, instance types, VPC configuration, subnet selection, environment-specific settings, resource retention behavior, feature flags, and monitoring configuration.


Engineering Analogy

Think of a CloudFormation template like a software application.

Parameters = Function Arguments

def deploy(environment):
    ...

CloudFormation: Environment = prod โ€” the template receives input and uses it to determine the deployment.

Mappings = Lookup Dictionary

instance_types = {
    "dev": "t3.micro",
    "staging": "t3.small",
    "prod": "t3.large"
}

CloudFormation Mappings serve the same purpose.

Intrinsic Functions = Built-in Operations

Ref        = retrieve a value
GetAtt     = retrieve an attribute
Sub        = substitute variables into a string
Join       = concatenate values
Select     = select an item
Split      = convert a string into a list
FindInMap  = perform a lookup
Parameters            =  Function Arguments
Mappings              =  Dictionary / Lookup Table
Intrinsic Functions    =  Built-in Operations
Resources              =  Infrastructure Output

This mental model makes complex CloudFormation templates much easier to understand.


Best Practices


Common Mistakes


Pro Tip

Think “Input โ†’ Lookup โ†’ Transform โ†’ Resource.”

When reading a complex CloudFormation template, trace values through the template in this order:

1. Where does the value come from?
             |
             v
2. Is it a Parameter?
             |
             v
3. Is it looked up in a Mapping?
             |
             v
4. Is an intrinsic function transforming it?
             |
             v
5. Which Resource consumes the final value?

For example:

Environment Parameter
        |
        v
!Ref Environment
        |
        v
!FindInMap EnvironmentMap
        |
        v
InstanceType
        |
        v
AWS::EC2::Instance

This approach is especially useful when troubleshooting CloudFormation templates. Instead of reading the template from top to bottom, follow the value. Ask: “What is this value, where did it come from, and how did CloudFormation transform it before passing it to the resource?” That question will often reveal configuration problems much faster than reading the entire template line by line.


Key Takeaways


Related Articles


References

System Context

โ† Back to Kb