Skip to main content
This article demonstrates how to use the CloudFormation !Sub substitution function to inject parameter values into ARNs and other strings, avoiding hard-coded resource names. Using !Sub makes templates reusable, easier to manage across environments, and helps eliminate brittle string literals.

Why use !Sub instead of hard-coded names

  • Keeps templates environment-agnostic and reusable.
  • Lets you supply values at stack creation time via Parameters.
  • Reduces copy/paste errors when reusing templates across accounts, regions, or partitions.

Example: Hard-coded bucket name

Here is an example policy where the bucket name is hard-coded inside the ARN:
The eden-kodekloud-bncv-bkt segment is fixed in the template. To make this template parameter-driven, replace the literal bucket name in the ARN with a !Sub expression that references a parameter.

Dynamic resource ARN with !Sub

Use !Sub with a placeholder like ${InputBucketName}. You can keep the Bucket property as !Ref (or use !Sub there as well). This example keeps Bucket: !Ref and uses !Sub only in the ARN:
Now the ${InputBucketName} placeholder is replaced with the value provided to the InputBucketName parameter when the stack is created.

Parameters and mappings (example)

Below is an example Mappings and Parameters section that pairs a bucket parameter with a developer selection. This demonstrates how !Sub works together with template inputs:
Using !Sub improves template readability and reusability. You can reference parameters in any string or ARN using the same ${ParamName} pattern, and the substitution happens at deploy time.

cfn-lint warning about hard-coded partition

Tooling like cfn-lint may warn about a hard-coded partition when an ARN includes arn:aws:.... That literal uses the aws partition and reduces portability if you plan to deploy to specialized partitions (for example, aws-us-gov or aws-cn). To make an ARN partition-agnostic, include the AWS::Partition pseudo parameter inside !Sub:
This ensures the partition (aws, aws-cn, aws-us-gov, etc.) is chosen automatically based on where the stack is deployed.
If you do not plan to deploy to AWS GovCloud or China partitions, keeping arn:aws:s3::: is acceptable in many cases. Use ${AWS::Partition} when you need true portability across partitions.

Linter severities (quick reference)

Best practices & checklist

  • Replace hard-coded resource names in ARNs with !Sub and ${ParameterName} to support parameterized deployments.
  • Use AWS::Partition inside !Sub if you require portability across AWS partitions.
  • Prefer !Sub for any string that includes parameters or pseudo parameters (for example, AWS::AccountId, AWS::Region, AWS::Partition).
  • Keep Bucket: !Ref InputBucketName (or Bucket: !Sub "${InputBucketName}") and use !Sub only where interpolation is required.
  • Run cfn-lint to catch portability and formatting issues, and apply linter guidance based on your deployment targets.

Summary

  • Use !Sub with ${ParameterName} to inject parameter values into ARNs and other strings.
  • Add ${AWS::Partition} inside !Sub when cross-partition portability is needed.
  • Treat cfn-lint messages as guidance: prioritize errors, evaluate warnings, and apply best-practice suggestions where beneficial.

Watch Video