CloudFormation protip: use !Sub instead of !Join
Tags: aws, cloudformation, programming, serverless
Published: 2019-05-12 14:14:55

---
title: CloudFormation protip: use !Sub instead of !Join
published: true
tags: AWS,CloudFormation,Programming,Serverless
canonical_url: https://theburningmonk.com/2019/05/cloudformation-protip-use-fnsub-instead-of-fnjoin/
---

CloudFormation supports a number of [intrinsic functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html) and `Fn::Join` (or `!Join`) is often used to construct parameterised names and paths.

The [Serverless framework](https://serverless.com/framework/), for instance, uses it extensively. A quick look in a CloudFormation it generates I can see `Fn::Join` used for:

- IAM policy names
- IAM role names
- IAM principals
- API Gateway URIs
- Resource ARNs

and many more.

But it’s not just the frameworks that are using `Fn::Join` heavily. They also show up in our own code all the time as well. For example, to construct the ARN for a resource, or the URI for an API Gateway endpoint.

![](https://theburningmonk.com/wp-content/uploads/2019/05/img_5cd77476f1b2d.png)

![](https://theburningmonk.com/wp-content/uploads/2019/05/img_5cd774833cfc3.png)

I find these very hard to comprehend, and my protip for you today is to use `Fn::Sub` (or the `!Sub` shorthand) instead.

Many folks would use `Fn::Sub` when they need to reference pseudo parameters such as `AWS::Region` and `AWS::AccountId`, for example:

```
!Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}'
```

But `Fn::Sub` also lets you provide your own parameters. For example:

```
!Sub
 - 'arn:aws:s3:::${Bucket}/\*'
 - { Bucket: Ref MyBucket }
```

The advantage over `Fn::Join` is that you can see the pattern of the interpolated string. Whereas with `Fn::Join` you’ll have to construct the pattern in your mind, which requires far more cognitive energy.

```
!Join
 - ''
 - - 'arn:aws:s3:::'
   - !Ref MyBucket
   - '/*'
```

Here are a few side-by-side comparisons to drive home the message.

Example 1: IAM role name

```
RoleName: # hello-world-dev-{region}-lambdaRole
 !Join
   - '-'
   - - 'hello-world'
     - 'dev'
     - !Ref 'AWS::Region'
     - 'lambdaRole'
```

with `Fn::Sub`:

```
PolicyName: !Sub 'hello-world-dev-${AWS::Region}-lambdaRole
```

Example 2: API Gateway integration URI

```
Uri: # arn:{partition}:apigateway:{region}:.../{lambda}/invocations
  !Join
    - ''
    - - 'arn:'
      - Ref: AWS::Partition
      - ':apigateway:'
      - Ref: AWS::Region
      - ':lambda:path/2015-03-31/functions/'
      - !GetAtt 'HelloLambdaFunction.Arn'
      - '/invocations'
```

with `Fn::Sub`:

```
Uri:
  !Sub
    - 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015/03/31/functions/${Function}/invocations'
    - { Function: !GetAtt 'HelloLambdaFunction.Arn' }
```

Example 3: Lambda permission for API Gateway

```
SourceArn: # arn:{partition}:execute-api:{region}:.../*/*
  !Join:
    - ''
    - - 'arn:'
      - Ref: AWS::Partition
      - ':execute-api:'
      - Ref: AWS::Region
      - ':'
      - Ref: AWS::AccountId
      - ':'
      - Ref: ApiGatewayRestApi
      - '/*/*'
```

with `Fn::Sub`:

```
SourceArn:
  !Sub
    - 'arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApi}/*/*'
    - { RestApi: Ref: ApiGatewayRestApi }
```

Suffice to say that the `Fn::Sub` version is easier to understand in every case! Now that you have seen what `Fn::Sub` can do, I hope you will prefer it to `Fn::Join` going forward.

If you’re using the Serverless framework, keep in mind that `Fn::Sub` is not natively supported. This is because the Serverless framework also uses the `${}` syntax to support its own [variables system](https://serverless.com/framework/docs/providers/aws/guide/variables/). However, as is often the case with the Serverless framework, you can work around this issue with a plugin. Check out the [serverless-cloudformation-sub-variables](https://github.com/santiagocardenas/serverless-cloudformation-sub-variables) plugin which lets you use `Fn::Sub` in the `serverless.yml`. You just need to use `#{VariableName}` instead of `${VariableName}`.

Finally, if you’re using the _Serverless_ framework and need more expressive power than the intrinsic functions can offer, then check out [this plugin](https://dev.to/theburningmonk/introducing-cloudformation-extrinsic-functions-33e1). It lets you use a number of “extrinsic” functions such as `Fn::Substring` or `Fn::StartsWith` anywhere in your `serverless.yml`.


The post [CloudFormation protip: use !Sub instead of !Join](https://theburningmonk.com/2019/05/cloudformation-protip-use-fnsub-instead-of-fnjoin/) appeared first on [theburningmonk.com](https://theburningmonk.com).

 ![](http://feeds.feedburner.com/~r/theburningmonk/~4/Tnt5S1OhlGE)