Terraform Planfiles
Atmos provides sophisticated planfile management for Terraform, enabling safe and predictable infrastructure changes through plan generation, storage, and application workflows.
Overview
A Terraform planfile is a binary file that contains the exact set of changes Terraform will make to your infrastructure. Atmos enhances Terraform's native planfile functionality by:
- Standardizing planfile naming and storage
- Enabling seamless plan-and-apply workflows
- Supporting both automatic and custom planfile management
- Integrating with CI/CD pipelines and approval workflows
Why Planfiles Are Important
Planfiles are one of Terraform's most powerful features for ensuring safe, predictable infrastructure changes. They solve a critical problem: ensuring that what you reviewed is exactly what gets applied.
The Problem Without Planfiles
Without planfiles, there's a dangerous gap between plan and apply:
- You run
terraform planand review the changes - Time passes (minutes, hours, or days)
- During
terraform apply:- Someone else might have modified the infrastructure
- Configuration files might have changed
- Provider APIs might return different data
- Remote state might have been updated
- Result: The applied changes differ from what was reviewed!
How Planfiles Solve This
A planfile is a snapshot that captures:
- The exact infrastructure state at planning time
- The precise changes Terraform will make
- All variable values and provider configurations
- The complete dependency graph
When you apply a planfile, Terraform uses this snapshot instead of re-calculating changes, guaranteeing that what you reviewed is what gets applied.
Benefits of Using Planfiles
1. Guaranteed Consistency
- No Drift: Changes applied match exactly what was planned, even if infrastructure or configuration changed
- Immutable Plans: Once generated, a planfile cannot be modified, ensuring integrity
- State Version Tracking: Planfiles capture the state version at plan time to detect if the state has changed before applying. Note that actual concurrency protection comes from your backend's state locking mechanisms, not from planfiles themselves
2. Enhanced Security and Compliance
- Audit Trail: Planfiles serve as immutable records of approved changes for compliance
- Review Process: Security teams can analyze planfiles before approval
- Approval Workflows: Enable separation of duties - developers plan, ops team approves and applies
- Policy Validation: Run security scanners (Checkov, tfsec, OPA) against planfiles. Use
atmos terraform generate planfileto create the JSON version needed by most security scanning tools
3. CI/CD Pipeline Safety
- Atomic Operations: Apply exactly what passed through your CI/CD tests
- Artifact Storage: Store planfiles in external storage (e.g., S3, GitHub Actions artifacts). Atmos provides a planfile storage GitHub Action for this purpose
- Change Documentation: Saved planfiles provide a record of what changes were planned, useful for understanding what was deployed (not for automated rollback)
- Multi-Stage Pipelines: Separate plan generation, validation, approval, and application stages
4. Operational Efficiency
- Faster Apply: No need to refresh state or recalculate the dependency graph (can be 50-70% faster)
- Reduced API Calls: Fewer cloud provider API calls during apply (important for rate limits)
- Predictable Timing: Apply duration is predictable since the work is pre-calculated
- Offline Review: Planfiles can be converted to JSON/YAML for review without Terraform access
5. Team Collaboration
- Async Workflows: One engineer can generate plans for another to review and apply
- Change Windows: Generate plans ahead of maintenance windows, apply during the window
- Knowledge Transfer: Planfiles document infrastructure changes for team learning
Planfile Limitations and Challenges
While planfiles provide significant benefits, they also have important limitations to understand:
Planfile Staleness
Planfiles become stale and must be recreated if:
- Infrastructure changes externally (e.g., manual changes, other automation)
- Terraform state is updated by other operations
- Configuration files are modified after plan generation
- Provider data sources return different values
Plan Comparison and Verification
When recreating planfiles, you cannot automatically verify they're identical to the original. Use atmos terraform plan-diff to compare plans and determine if they are effectively the same or have material differences.
# Generate new planfile
atmos terraform plan vpc -s dev -out vpc-dev.planfile
# Compare with previous plan to detect drift
atmos terraform plan-diff vpc -s dev
IAM Role and Authentication Issues
If different IAM roles are used for plan vs apply, the planfile will cause failures:
- Planfiles embed the IAM role used during plan generation (via provider
assume_roleconfiguration) - If you apply with a different IAM role, Terraform will fail because the embedded credentials don't match
- Solution: Use the same IAM role for both plan and apply, or regenerate the planfile with the apply role
Regeneration and Re-verification
When any of these issues occur:
- Regenerate the planfile with current state and credentials
- Re-verify the plan matches expectations (use
plan-diffif comparing to a previous plan) - Re-run approval workflows if your process requires it
Backend Limitations
Not all Terraform backends support saving planfiles locally with the -out flag. This is a limitation of Terraform and OpenTofu core, not Atmos. Atmos works within these constraints and provides workarounds where possible.
Understanding Backend Types
Terraform backends fall into two categories regarding planfile support:
- Standard Backends: Store state only, support local planfile generation
- Enhanced Backends: Manage both state and operations remotely, don't support local planfiles
When using -backend-config or hardcoding backend credentials in your configuration, Terraform embeds these values in plan files. This creates serious security risks:
- Credentials Exposed: Sensitive data like usernames, passwords, and tokens are stored in plaintext within the planfile
- CI/CD Breakage: Job-specific or time-limited tokens become invalid between plan and apply stages
- Compliance Violations: Planfiles containing secrets cannot be safely stored, shared, or committed to version control
The HTTP backend is particularly problematic: While it technically supports terraform plan -out, the embedded credentials make it effectively unusable in any production or CI/CD environment. For all practical purposes, treat the HTTP backend as not supporting planfiles.
Best Practice: Use environment variables for backend authentication or choose backends that support secure credential management.
Backends That DO NOT Support Local Planfiles
The following backends have limitations with terraform plan -out=<file>:
| Backend | Type | Actual Limitation | Recommended Approach |
|---|---|---|---|
| Remote Backend | Enhanced | Does not support saving execution plans locally. Returns error: "The 'remote' backend does not support saving the generated execution plan locally" | Use remote execution mode or migrate to standard backend with skip_planfile: true in Atmos |
| Terraform Cloud | Enhanced | Remote execution mode doesn't allow local plan output | Use VCS-driven workflow or configure skip_planfile: true in Atmos |
| Terraform Enterprise | Enhanced | Same as Terraform Cloud - remote execution limitation | Use VCS-driven workflow or configure skip_planfile: true in Atmos |
| HTTP Backend | Standard | ⚠️ Security Risk: While technically supports -out, backend credentials are embedded in planfiles making it effectively unusable | Do not use planfiles with HTTP backend. Use environment variables for auth or switch backends |
Backends That Support Planfiles
All standard backends support local planfile generation. These are the most commonly used:
| Backend | Storage Type | Best For | Key Features |
|---|---|---|---|
| S3 | AWS S3 | AWS infrastructure | • DynamoDB for locking • Encryption at rest • Versioning support |
| GCS | Google Cloud Storage | GCP infrastructure | • Native state locking • Customer-managed encryption keys • Versioning support |
| Azure Blob | Azure Storage | Azure infrastructure | • Native locking via blob leases • Encryption at rest • Soft delete capability |
| Local | Filesystem | Development/testing | • Simple setup • No external dependencies • Not for production teams |
| Consul | HashiCorp Consul | Multi-cloud setups | • Distributed storage • High availability • Built-in encryption |
| PostgreSQL | Database | Centralized management | • ACID compliance • Existing database infrastructure • SQL-based queries |
| Kubernetes | K8s Secrets | Kubernetes-native | • Native K8s integration • RBAC support • Namespace isolation |
| OSS | Alibaba Cloud OSS | Alibaba Cloud | • TableStore for locking • Server-side encryption |
| COS | Tencent Cloud COS | Tencent Cloud | • Native locking support • Cross-region replication |
Identifying Backend Limitations
Common Error Messages
When using a backend that doesn't support planfiles, you'll see one of these errors:
Terraform Cloud/Enterprise:
Error: Saving a generated plan is currently not supported
The "remote" backend does not support saving the generated execution
plan locally at this time.
Remote Backend:
Error: Run variables are currently not supported
The "remote" backend does not support setting run variables at this time.
Currently the only to way to pass variables is by creating a '*.auto.tfvars'
variables file or by setting environment variables.
HTTP Backend with Credentials:
Error: Error loading state: HTTP remote state endpoint requires auth
The plan was created with different credentials than those being used
to apply it.
Testing Your Backend
Working with Non-Supporting Backends
If your backend doesn't support planfiles, you have several options:
Option 1: Skip Planfiles
Configure Atmos to skip planfile generation:
components:
terraform:
plan:
skip_planfile: true # Disable for all components
Or per-command:
Option 2: Use Backend-Specific Workflows
For Terraform Cloud/Enterprise:
components:
terraform:
backend:
type: remote
organization: your-org
plan:
skip_planfile: true # Required for remote backend
How Atmos Manages Planfiles
Automatic Planfile Generation
When you run atmos terraform plan, Atmos automatically:
- Generates a planfile with a standardized name
- Stores it in the component's working directory
- Makes it available for subsequent apply operations
Automatic Planfile Naming
When no custom planfile name is specified with -out, Atmos automatically generates a planfile name following this pattern:
# Without folder prefix
<stack>-<component>.planfile
# With folder prefix
<stack>-<folder_prefix>-<component>.planfile
# Examples:
dev-vpc.planfile # Stack: dev, Component: vpc
prod-us-east-1-database.planfile # Stack: prod, Folder: us-east-1, Component: database
staging-platform-kubernetes.planfile # Stack: staging, Folder: platform, Component: kubernetes
This automatic naming ensures:
- Consistent planfile identification across teams
- No accidental planfile overwrites between runs
- Easy correlation between planfiles and their stack/component
Planfile Storage Location
Planfiles are stored in the component's working directory:
## Working with Planfiles in Practice
### Binary Planfiles (Native Terraform)
When using supported backends, Atmos automatically generates binary planfiles:
```bash
# Atmos generates: dev-vpc.planfile
atmos terraform plan vpc -s dev
# Apply the generated planfile
atmos terraform apply vpc -s dev --from-plan
# Or specify a custom planfile name
atmos terraform plan vpc -s dev -out=my-custom.tfplan
atmos terraform apply vpc -s dev --planfile my-custom.tfplan
JSON/YAML Planfiles with atmos terraform generate planfile
For enhanced security scanning, policy validation, or when binary planfiles aren't suitable, use Atmos's JSON/YAML planfile generation:
# Generate JSON planfile for security scanning
atmos terraform generate planfile vpc -s dev --file-template plan-{{.stack}}-{{.component}}.json
# Generate YAML planfile for human review
atmos terraform generate planfile vpc -s dev --file-template plan-{{.stack}}-{{.component}}.yaml
Integration with Security and Compliance Tools
JSON planfiles enable integration with security scanning and policy tools:
# Generate JSON planfile for security scanning
atmos terraform generate planfile vpc -s prod --file-template prod-vpc.json
# Scan with Wiz.io or similar tools
wiz-cli iac scan --format terraform-plan prod-vpc.json
# Check with Open Policy Agent (OPA)
opa eval -d policies/ -i prod-vpc.json "data.terraform.deny[msg]"
# Validate with Checkov
checkov --framework terraform_plan -f prod-vpc.json
# Analyze with Terrascan
terrascan scan -i tfplan -f prod-vpc.json
Benefits of JSON/YAML planfiles:
- Security Scanning: Integrate with tools like Wiz.io, Snyk, Checkov
- Policy as Code: Validate with OPA, Sentinel, or custom policies
- Human Review: YAML format is easy to read and review
- Version Control: Can be safely committed (no binary data)
- Backend Independent: Works with any backend, including those that don't support binary planfiles
- Audit Trail: Creates reviewable record of planned changes
Comparing Planfiles with atmos terraform plan-diff
Compare any two planfiles to understand differences:
# Compare two JSON planfiles
atmos terraform plan-diff --file plan1.json --file2 plan2.json
# Compare different formats
atmos terraform plan-diff --file plan1.yaml --file2 plan2.json --format yaml
# Compare binary planfile with JSON (after converting)
atmos terraform generate planfile vpc -s dev --file-template current.json
atmos terraform plan-diff --file baseline.json --file2 current.json
This performs a semantic comparison of the plan data structures, not a naive text diff.
components/ └── terraform/ └── vpc/ ├── main.tf ├── variables.tf ├── outputs.tf └── dev-vpc.planfile # Generated planfile
## Working with Planfiles
### Basic Plan and Apply Workflow
The most common workflow is to generate a plan, review it, and then apply it:
```bash
# Step 1: Generate a plan (automatically creates a planfile)
$ atmos terraform plan vpc -s dev
# Review the plan output...
# Step 2: Apply the exact plan that was generated
$ atmos terraform apply vpc -s dev --from-plan
Custom Planfile Locations
You can specify custom locations for planfiles using the standard Terraform -out flag:
Skipping Planfile Generation
In some cases, you may want to run a plan without generating a planfile:
components:
terraform:
plan:
skip_planfile: true # Disable planfile generation globally
Planfile Flags and Options
Plan Command Flags
| Flag | Description | Example |
|---|---|---|
-out=FILE | Save plan to specific file | atmos terraform plan vpc -s dev -out=my.planfile |
--skip-planfile | Skip planfile generation | atmos terraform plan vpc -s dev --skip-planfile |
Apply Command Flags
| Flag | Description | Example |
|---|---|---|
--from-plan | Use Atmos-generated planfile | atmos terraform apply vpc -s dev --from-plan |
--planfile FILE | Use specific planfile | atmos terraform apply vpc -s dev --planfile my.planfile |
GitLab CI Example
If using GitLab's built-in Terraform state management, planfiles are not supported. GitLab manages the complete plan/apply workflow internally. Use GitLab's native integration instead of Atmos planfiles.
For standard backends (S3, GCS, Azure) with GitLab CI:
stages:
- plan
- apply
variables:
# Important: Use consistent credentials across jobs
TF_VAR_token: ${CI_JOB_TOKEN} # Same token for all jobs
plan:
stage: plan
script:
- atmos terraform plan vpc -s prod
artifacts:
paths:
- components/terraform/vpc/prod-vpc.planfile
expire_in: 1 day
apply:
stage: apply
dependencies:
- plan
script:
- atmos terraform apply vpc -s prod --from-plan
only:
- main
when: manual # Require manual approval
Terraform Cloud Integration
Terraform Cloud doesn't support the -out flag for planfiles. When using Terraform Cloud:
Configuration
components:
terraform:
plan:
skip_planfile: true # Required for Terraform Cloud
Environment Variable
export ATMOS_COMPONENTS_TERRAFORM_PLAN_SKIP_PLANFILE=true
Command Line
atmos terraform plan vpc -s dev --skip-planfile
Advanced Use Cases
Plan Comparison
Compare two different plans using atmos terraform plan-diff:
JSON/YAML Planfiles
Generate planfiles in JSON or YAML format for integration with other tools:
Multi-Component Workflows
Apply plans for multiple components in sequence:
#!/bin/bash
# generate-and-apply-all.sh
components=("vpc" "database" "kubernetes" "application")
stack="prod"
# Generate all plans
for component in "${components[@]}"; do
echo "Planning $component..."
atmos terraform plan "$component" -s "$stack"
done
# Review and apply
read -p "Apply all plans? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
for component in "${components[@]}"; do
echo "Applying $component..."
atmos terraform apply "$component" -s "$stack" --from-plan
done
fi
Example 1: Multi-Environment Deployment
Deploy the same configuration across multiple environments with confidence:
#!/bin/bash
# deploy-all-environments.sh
environments=("dev" "staging" "prod")
component="api-service"
# Generate all plans first
for env in "${environments[@]}"; do
echo "Planning $component in $env..."
atmos terraform plan "$component" -s "$env" \
-out="${env}-${component}-$(date +%Y%m%d-%H%M%S).planfile"
done
# Review all plans
echo "Please review all generated plans..."
ls -la *.planfile
# Apply after approval
read -p "Apply all plans? (yes/no) " -r
if [[ $REPLY == "yes" ]]; then
for env in "${environments[@]}"; do
planfile=$(ls ${env}-${component}-*.planfile | head -n1)
echo "Applying $planfile..."
atmos terraform apply "$component" -s "$env" --planfile "$planfile"
done
fi
Example 2: Blue-Green Deployment
Use planfiles to ensure both environments are updated identically:
# Step 1: Plan both blue and green environments
atmos terraform plan app -s prod-blue -out=blue.planfile
atmos terraform plan app -s prod-green -out=green.planfile
# Step 2: Deploy to green (inactive) first
atmos terraform apply app -s prod-green --planfile green.planfile
# Step 3: Switch traffic to green
atmos terraform apply load-balancer -s prod --var="active_env=green"
# Step 4: Update blue (now inactive)
atmos terraform apply app -s prod-blue --planfile blue.planfile
Example 3: Compliance-Required Workflow
For regulated environments requiring approval and audit trails:
# Developer generates plan
atmos terraform plan database -s prod -out=change-request-12345.planfile
# Convert to JSON for compliance scanning
atmos terraform generate planfile database -s prod \
--planfile change-request-12345.planfile \
--format=json \
--file=change-request-12345.json
# Run compliance checks
checkov --file change-request-12345.json --framework terraform_plan
opa eval -d /policies -i change-request-12345.json "data.terraform.deny[msg]"
# After approval, operations team applies
atmos terraform apply database -s prod --planfile change-request-12345.planfile
# Archive for audit
aws s3 cp change-request-12345.planfile \
s3://audit-bucket/terraform/$(date +%Y/%m/%d)/change-request-12345.planfile
Best Practices
When to Use Planfiles
Use planfiles when:
- You need guaranteed consistency between plan and apply
- Multiple team members review changes before applying
- Compliance requires an audit trail of approved changes
- You want to prevent drift between planning and execution
- Running in automated pipelines where plans need approval
Skip planfiles when:
- Working in development environments with rapid iteration
- Using backends that don't support them (Remote, Terraform Cloud)
- Backend credentials would be embedded (HTTP backend)
- Real-time infrastructure state is critical
Security Considerations
- Never commit binary planfiles to version control - They may contain sensitive data
- Use environment variables for backend authentication - Avoid
-backend-configwith sensitive values - Consider JSON planfiles for sensitive environments - Use
atmos terraform generate planfilefor reviewable, scannable output - Set appropriate file permissions - Planfiles should be readable only by authorized users
- Clean up old planfiles - Remove after applying or when no longer needed
Choosing the Right Approach
| Scenario | Recommended Approach | Command |
|---|---|---|
| Production deployment with approval | Binary planfile | atmos terraform plan vpc -s prod |
| Security scanning required | JSON planfile | atmos terraform generate planfile vpc -s prod --file-template plan.json |
| Using HTTP backend | Skip planfiles | atmos terraform plan vpc -s prod --skip-planfile |
| Rapid development iteration | Skip planfiles | atmos terraform deploy vpc -s dev |
| Compliance audit required | JSON planfile + version control | atmos terraform generate planfile with Git |
Security Considerations
- Never commit binary planfiles to version control - They may contain sensitive data
- Use environment variables for backend authentication - Avoid
-backend-configwith sensitive values - Consider JSON planfiles for sensitive environments - Use
atmos terraform generate planfilefor reviewable, scannable output - Set appropriate file permissions - Planfiles should be readable only by authorized users
- Clean up old planfiles - Remove after applying or when no longer needed
Choosing the Right Approach
| Scenario | Recommended Approach | Command |
|---|---|---|
| Production deployment with approval | Binary planfile | atmos terraform plan vpc -s prod |
| Security scanning required | JSON planfile | atmos terraform generate planfile vpc -s prod --file-template plan.json |
| Using HTTP backend | Skip planfiles | atmos terraform plan vpc -s prod --skip-planfile |
| Rapid development iteration | Skip planfiles | atmos terraform deploy vpc -s dev |
| Compliance audit required | JSON planfile + version control | atmos terraform generate planfile with Git |
1. Always Review Plans
Never apply infrastructure changes without reviewing the plan first:
# Good: Plan, review, then apply
atmos terraform plan vpc -s prod
# ... review the output ...
atmos terraform apply vpc -s prod --from-plan
# Avoid: Direct apply without review (except in dev)
atmos terraform apply vpc -s prod -auto-approve
3. Clean Up Old Planfiles
Planfiles can contain sensitive information. Clean them up regularly:
# Clean component directory (removes planfiles and varfiles)
atmos terraform clean vpc -s dev
# Or manually remove old planfiles
find components/terraform -name "*.planfile" -mtime +7 -delete
4. Secure Planfile Storage
When storing planfiles in CI/CD:
- Encrypt planfiles at rest and in transit
- Set appropriate retention periods (typically 1-7 days)
- Restrict access to planfiles containing sensitive data
- Never commit planfiles to version control
5. Validate Plans Before Applying
Use tools to validate planfiles before applying:
# Generate planfile in JSON format
atmos terraform generate planfile vpc -s prod --format=json
# Validate with Checkov
checkov --file prod-vpc.planfile.json --framework terraform_plan
# Validate with OPA
opa eval -d policies/ -i prod-vpc.planfile.json "data.terraform.deny[msg]"
Troubleshooting
Common Issues
Planfile Not Found
Error: Planfile not found at expected location
Solution: Ensure you've run atmos terraform plan first, or check the planfile path.
Stale Planfile
Error: Saved plan is stale; either terraform.tfstate was modified, or the plan file is out of date
Solution: Regenerate the plan with atmos terraform plan.
Terraform Cloud Compatibility
Error: Run variables are currently not supported
Solution: Use --skip-planfile flag or configure skip_planfile: true in atmos.yaml.
Debugging
Enable debug logging to see planfile operations:
# Enable debug logs
export ATMOS_LOGS_LEVEL=Debug
# Run commands
atmos terraform plan vpc -s dev
atmos terraform apply vpc -s dev --from-plan
Related Documentation
atmos terraform plan- Plan command referenceatmos terraform apply- Apply command referenceatmos terraform deploy- Deploy command referenceatmos terraform plan-diff- Plan comparisonatmos terraform generate planfile- Generate JSON/YAML planfiles- Terraform Configuration - Configure Terraform behavior