Skip to main content

Migrating from Rain / Raw CloudFormation

Rain is no longer actively maintained. If you built a deploy workflow around it — rain deploy, rain watch, a Makefile calling rain fmt in CI — that workflow now has no owner. Your CloudFormation templates are still good. What's gone is the CLI, the artifact-bucket bootstrapping, and the drift/changeset ergonomics Rain gave you on top of the raw AWS CLI. Atmos's native aws/cloudformation component type replaces that layer without asking you to rewrite a single resource.

Experimental

Why This Guide?​

AWS archived Rain upstream in 2026. If you're one of its users, you're likely facing one of two situations:

  • You used Rain's CLI (deploy, diff, watch, fmt, ls, bootstrap) to wrap the raw AWS CLI/API with something more usable, and now that tool has no future.
  • You used Rain's !Rain:: template directives (Constant, Env, Include, Embed, S3, Module) to work around gaps in plain CloudFormation, and your templates won't deploy anywhere without first resolving those directives.

This guide covers both. There is no Rain compatibility layer in Atmos — no !Rain:: directive preprocessing, no Rain config-file support — so if your templates use directives, resolving them is the first real step, not an afterthought.

Crawl, Walk, Run​

  • Crawl: Get a template deploying through Atmos in about 20 minutes (this guide)
  • Walk: Directive resolution, artifact-bucket provisioning, and cross-component Outputs
  • Run: Advanced features when you need them (StackSets, provision targets, inheritance)

Crawl: Get Running in 20 Minutes​

What You're Going To Do​

  1. Install Atmos
  2. Resolve any !Rain:: directives in your template (skip if you're on raw CloudFormation already)
  3. Create a minimal atmos.yaml
  4. Create one stack YAML file
  5. Run atmos aws cloudformation plan

Step 1: Install Atmos​

# macOS/Linux (Homebrew)
brew install atmos

# Go
go install github.com/cloudposse/atmos@latest

# Or download from GitHub releases

See the full Installation Guide for all options.

Step 2: Resolve !Rain:: Directives (If Any)​

If your templates don't use !Rain:: directives, skip to Step 3.

Atmos never preprocesses a file-based CloudFormation template — path: points at a file that gets read and submitted to the CloudFormation API as-is. That means a template still containing !Rain::* tags is not valid CloudFormation as far as Atmos (or CloudFormation itself) is concerned. Resolve each directive to a plain-CloudFormation or Atmos-native equivalent first:

!Rain:: directiveWhat it didAtmos-native replacement
ConstantInjected a named constant's value into the template at preprocess timeA CloudFormation Parameters: entry, fed from the component's parameters: section in stack config
EnvInjected an environment variable's value at preprocess timeSame as Constant, with the stack-config value set via !env
IncludeMerged an external JSON/YAML fragment into the template at preprocess timeCloudFormation's own native Fn::Transform/AWS::Include intrinsic for fragment reuse (a CloudFormation feature, not Rain- or Atmos-specific); AWS CDK for anything more structural
EmbedInlined a local file's contents as a string literal (e.g. Lambda inline code) at preprocess timeInline the content directly with a YAML block scalar for small scripts; pre-upload larger assets to S3 and reference the URL directly
S3Uploaded a local file/directory to S3 and rewrote the reference at preprocess timePartial support today — see S3 Packaging Is Size-Triggered, Not Asset-Aware below
ModuleClient-side, multi-file template composition (marked experimental in Rain's own docs)Not supported — use AWS CDK for real modular template composition

Before/After: Constant/Env → Parameters​

# template.yaml (Rain-preprocessed)
Resources:
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Rain::Constant BucketNamePrefix-bucket
Tags:
- Key: Owner
Value: !Rain::Env DEPLOY_OWNER

Before/After: Embed → Inline Block Scalar​

Resources:
Function:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: !Rain::Embed handler.py

Step 3: Create Minimal atmos.yaml​

Point Atmos to where your CloudFormation templates live:

atmos.yaml
base_path: "./"

components:
"aws/cloudformation":
base_path: "components/cloudformation"

stacks:
base_path: "stacks"
included_paths:
- "deploy/**/*"
excluded_paths:
- "**/_defaults.yaml"
Customize Your Structure

If your templates already live in a directory like cloudformation/ or infra/, point components."aws/cloudformation".base_path there directly instead of moving files.

Step 4: Create Your First Stack​

stacks/deploy/dev.yaml
name: dev

components:
"aws/cloudformation":
vpc:
path: template.yaml
stack_name: acme-plat-dev-vpc
parameters:
CidrBlock: "10.0.0.0/16"
capabilities:
- CAPABILITY_IAM

Atmos parameters: requires a map from parameter names to values. If your existing JSON file already uses that format, include it directly. If it uses the AWS CLI ParameterKey/ParameterValue array format, convert it to a map first and keep the original file for your existing workflow.

For example, convert this AWS CLI parameter array:

[
{"ParameterKey": "CidrBlock", "ParameterValue": "10.0.0.0/16"},
{"ParameterKey": "Environment", "ParameterValue": "dev"}
]

into a new parameter-map file:

params/dev-parameters.json
{
"CidrBlock": "10.0.0.0/16",
"Environment": "dev"
}

Include the converted file in the stack:

stacks/deploy/dev.yaml
components:
"aws/cloudformation":
vpc:
path: template.yaml
stack_name: acme-plat-dev-vpc
parameters: !include ../../params/dev-parameters.json
capabilities:
- CAPABILITY_IAM

The !include function parses JSON/YAML natively and resolves paths relative to the stack file. It does not convert AWS CLI parameter arrays into maps. Do not include an AWS CLI array directly: the current parameter handling silently ignores its values, leaving those parameters unspecified.

The AWS API's UsePreviousValue flag cannot be set through Atmos's parameters: map. Supply explicit values instead; entries using that flag must be replaced with the intended values before conversion. UsePreviousValue is not a literal parameter value.

Step 5: Run Atmos​

rain deploy template.yaml acme-plat-dev-vpc --params CidrBlock=10.0.0.0/16
rain diff template.yaml acme-plat-dev-vpc

deploy streams per-resource stack events live as they converge — the same "watch it happen" experience Rain's own deploy animation gave you — and ends with a rendered summary of the stack's Outputs, so you get that view both at deploy time and on demand afterward with atmos aws cloudformation output vpc -s dev.

You're now running Atmos.


What Just Happened?​

Key Differences at a Glance​

AspectRainAtmos
Templates.yaml/.json, optionally with !Rain::* directivesSame templates, directives resolved to plain CloudFormation
CLIrain deploy/diff/watch/fmt/ls/bootstrap/...atmos aws cloudformation <verb> (alias cfn) — see the verb cross-reference
Config--params flags or a parameters JSON fileStack YAML parameters: map (or !include a JSON map; convert AWS CLI arrays first); UsePreviousValue is unsupported
Artifact bucketAuto-created silently on first useExplicit atmos aws cloudformation backend create, or opt-in provision.backend.enabled: true
EnvironmentsSeparate command invocations per stack nameStack YAML files, with inheritance and imports
Cross-stack valuesManual aws cloudformation describe-stacks callsatmos aws cloudformation output, or !aws.cloudformation.output for cross-component consumption

What Stays The Same​

  • Your CloudFormation templates work as-is, once any !Rain:: directives are resolved
  • Your resource definitions, intrinsic functions (!Ref, !GetAtt, !Sub, ...), and capabilities are untouched
  • Parameter values can be reused through !include: convert AWS CLI arrays to maps and replace UsePreviousValue entries with explicit values

What You Added​

  • atmos.yaml — tells Atmos where your templates live
  • Stack YAML files — one per environment, replacing per-invocation --params flags

Walk: Immediate Value​

1. Rain → Atmos Verb Cross-Reference​

Rain commandAtmos-native equivalentNotes
rain deployatmos aws cloudformation deploydeploy = apply with --auto-approve implied
rain diffatmos aws cloudformation diff (or plan)Same operation, two names — both create and render a changeset without executing it
rain fmtatmos aws cloudformation fmt [--check]Native comment-preserving YAML round-trip — there's no cfn-format binary to shell out to anymore
rain catatmos aws cloudformation get template [--original]Fetches the deployed stack's template via GetTemplate
rain lsatmos aws cloudformation listAccount-wide, annotated with whether each stack matches a configured component's stack_name
rain logatmos aws cloudformation logs [--chart]Combined event log across a stack and its nested stacks
rain watchatmos aws cloudformation watchAttaches to a stack's in-progress or already-terminal operation
rain treeatmos aws cloudformation treeNested-stack/resource dependency graph
rain rmatmos aws cloudformation deleteRespects termination_protection — never silently disables it
rain bootstrapatmos aws cloudformation backend createProvisions the S3 artifact bucket; provision.backend.enabled: true does it automatically instead
rain buildNot supported — use atmos scaffoldSkeleton-template generation is a dev-time concern, not a component-type verb
rain forecastNot supported — use plan/diff + validateChangeset review plus server-side validation cover the same question
rain cc (Cloud Control passthrough)Not supportedNo equivalent planned
note

This table covers the Rain verbs referenced above. If you relied on a Rain subcommand not listed here, check the full CLI command reference — atmos aws cloudformation also ships verbs with no Rain precedent at all, like output and drift detect/drift describe, covered next.

2. Outputs, On Demand​

Rain showed you a stack's Outputs at the end of rain deploy, but offered no way to get that view back afterward without a manual describe-stacks call. Atmos renders the same summary both at deploy time and on demand:

atmos aws cloudformation output vpc -s dev
atmos aws cloudformation output vpc -s dev VpcId
atmos aws cloudformation output vpc -s dev --format=github

Other components — Terraform, Helm, another CloudFormation stack — can consume those Outputs directly:

stacks/deploy/dev.yaml
components:
"aws/cloudformation":
eks-vpc-link:
parameters:
VpcId: !aws.cloudformation.output vpc VpcId

See the !aws.cloudformation.output function for the full cross-component story, including the Terraform↔CloudFormation interop bridge.

3. Drift Detection as a First-Class Verb​

Rain only implied drift support through its stack-monitoring workflow. Atmos exposes it directly:

atmos aws cloudformation drift detect vpc -s dev
atmos aws cloudformation drift describe vpc -s dev

4. Provisioning the Artifact Bucket​

Rain auto-created its artifact bucket silently on first use. Atmos never does this by default — provision it explicitly, mirroring atmos terraform backend create:

atmos aws cloudformation backend create vpc -s dev

Or opt into the same automatic provisioning Terraform components get:

stacks/deploy/dev.yaml
components:
"aws/cloudformation":
vpc:
provision:
backend:
enabled: true
targets:
artifacts:
kind: aws/s3
bucket: acme-plat-cfn-artifacts

S3 Packaging Is Size-Triggered, Not Asset-Aware​

Be precise with yourself about this one before promising it to a team: apply/deploy automatically uploads the template body itself to the component's kind: aws/s3 provision target when it exceeds CloudFormation's 51,200-byte inline limit — the same problem aws cloudformation package/Rain's pkg solve. What it does not do yet is rewrite local-asset references inside the template (Lambda source zips, nested-stack templates referenced by relative path) the way !Rain::S3, aws cloudformation package, or Rain's pkg do. If your templates depend on that, pre-upload those assets to S3 out-of-band — a hook, a build step, an existing pipeline — and reference the resulting S3 location directly in the template until asset-aware packaging ships.


Run: When You're Ready​

StackSets​

Multi-account/multi-region orchestration, once you need it:

atmos aws cloudformation stackset create vpc -s dev
atmos aws cloudformation stackset instances vpc -s dev

Changesets, Managed Explicitly​

apply/deploy create and execute a changeset implicitly. For a two-phase pipeline (create and review in one job, execute in another), manage changesets directly:

atmos aws cloudformation changeset create vpc -s dev
atmos aws cloudformation changeset execute vpc -s dev --changeset-name <name>

Component Inheritance and Catalogs​

Reuse configuration across environments the same way Terraform/Helm components do:

stacks/catalog/vpc-defaults.yaml
components:
"aws/cloudformation":
vpc-defaults:
metadata:
type: abstract
capabilities:
- CAPABILITY_IAM
stacks/deploy/dev.yaml
components:
"aws/cloudformation":
vpc:
metadata:
component: vpc
inherits:
- vpc-defaults
path: template.yaml
parameters:
CidrBlock: "10.0.0.0/16"

See Component Inheritance and the full aws/cloudformation stack-configuration reference for every available section.


Why It's Worth It​

Real Benefits You'll Feel Immediately​

  • No orphaned tool — aws/cloudformation is SDK-native and maintained as part of Atmos, not a third-party binary that can be archived out from under you
  • Same "watch it happen" experience — live per-resource event streaming during apply/deploy
  • Outputs on demand — the deploy-time summary is also a standing command, not a one-time view
  • Drift detection as a first-class verb, not an inferred side effect of monitoring
  • One orchestration model — the same --all/--affected/depends_on DAG ordering your Terraform and Helm components already use, now covering CloudFormation stacks too

What Atmos Won't Do​

  • Won't preprocess your templates — every !Rain:: directive must be resolved to plain CloudFormation or Atmos-native config before a template is accepted
  • Won't rewrite local asset references automatically — see S3 Packaging Is Size-Triggered above
  • Won't give you a client-side module system — use AWS CDK for genuine multi-file template composition

Migration Checklist​

  • Install Atmos CLI (Installation Guide)
  • Resolve any !Rain:: directives in templates being migrated
  • Create atmos.yaml pointing at your existing template location
  • Create your first stack YAML (start with dev)
  • Test with atmos aws cloudformation plan <component> -s dev
  • Deploy with atmos aws cloudformation deploy <component> -s dev
  • Confirm Outputs match what was already deployed (atmos aws cloudformation output)
  • Create remaining stack files (staging, prod)
  • (Optional) Provision the artifact bucket with backend create or provision.backend.enabled: true
  • (Optional) Explore inheritance and catalogs for shared configuration
  • (Optional) Set up StackSets for multi-account/multi-region delivery

Next Steps​

You just did Crawl — you're running Atmos!

Walk: Explore these next:

Run: When you're ready for advanced features:


Common Questions​