Skip to main content

Migrate from Rain Without Rewriting Templates

· 3 min read
Erik Osterman
Founder @ Cloud Posse

Rain, the AWS CloudFormation CLI, was archived in July 2026. Teams that deploy with it need a replacement, and the aws/cloudformation component now has a native answer for every Rain directive, config file, and command. A new migration guide walks through it.

The Problem​

A Rain template is not plain CloudFormation. Rain rewrote !Rain::Env, !Rain::Include, !Rain::Embed, and !Rain::S3 directives before deployment. Atmos sends a template file to CloudFormation as written, and until now the only error a migrating team saw came back from the CloudFormation API: "YAML not well-formed (line 20, column 14)", with no mention of Rain.

Keeping a template file and using Atmos YAML functions inside it was not possible either. Pulling a template into template: with !include quietly turned every !GetAtt Role.Arn into the string Role.Arn, and an AWS CLI tags file deployed a stack with no tags at all.

What Changed​

A template that still contains Rain directives now fails locally, before any AWS call, and names the Atmos-native replacement for each directive it found.

CloudFormation's short-form intrinsics (!Ref, !Sub, !GetAtt, and the rest) are accepted in inline templates and in templates pulled in with !include, and rewritten to their long form on the way out. A template file can be included verbatim.

The !include function gained an opt-in | eval modifier. By default an included file is still data. With | eval, the YAML functions inside it are evaluated, which is how !Rain::Env becomes !env, !Rain::Include becomes a nested !include, and !Rain::Embed becomes !include of a script file:

components:
"aws/cloudformation":
app:
template: !include ../../components/cloudformation/app/template.yaml | eval

Uploads stay out of templates. YAML functions never change infrastructure, so !Rain::S3 maps to archive and publish hook steps, and those hooks now also fire on changeset create and changeset execute, the Atmos equivalents of rain deploy --no-exec and rain deploy --changeset.

Several silent failures became clear errors: a list-shaped tags: is rejected with the reshape recipe and the tags: !labels bridge in the hint, a missing packaging bucket reports the command that creates it on every preview and deploy command, UsePreviousValue on a first deployment explains why there is no previous value, and !env warns when a variable is unset and has no default.

How to Use It​

Start with the Rain migration guide. It maps each directive, parameter file, and command, and its examples are the ones that were run against both a local emulator and a real AWS account while writing it. Install the atmos-migration agent skill to let an AI coding assistant apply the same mapping to your repository:

atmos ai skill install atmos-migration