
September 10, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
Your team opens a Terraform pull request. Someone runs terraform plan locally, pastes the output into a comment, and hopes nothing changed before merge. That workflow breaks under pressure. Atlantis: Pull-Request Automation for Terraform fixes it by running plan and apply from one server, posting results on the PR, and locking projects so two changes cannot fight over the same state. If you already treat infrastructure as code, as covered in our Infrastructure as Code with Terraform practical guide, Atlantis is the missing review layer between Git and your remote backend.
terraform plan on pull requests, posts formatted output as PR comments, and runs apply only after an approved merge or explicit comment—centralising execution, locking state, and keeping every change auditable.What is Atlantis and how does pull-request automation for Terraform work?
Atlantis is an open-source Go application maintained at runatlantis/atlantis on GitHub. It sits between your Git host and your Terraform code. When a developer opens or updates a pull request, Atlantis clones the branch, discovers which Terraform projects changed, runs plan, and posts the output back to the PR thread.
After review, a team member comments atlantis apply. Atlantis runs terraform apply using credentials stored on the server—not on a laptop. Every command is logged. Every plan is tied to a commit SHA. That is the core value of Atlantis pull-request automation for Terraform: infrastructure changes follow the same review path as application code.
Core commands developers use
Atlantis responds to PR comments. The ones you will use daily:
atlantis plan— re-runs plan after new commitsatlantis apply— applies the approved plan for that PRatlantis unlock— releases a stuck project lockatlantis plan -p staging— targets a named project fromatlantis.yaml
Plans run automatically on opened and synchronized PRs when autoplan is enabled. Applies never run without an explicit comment or merge policy you configure. That separation mirrors how I run build pipeline automation best practices on application repos: build on every push, deploy only after approval.
How do you install and configure Atlantis for Terraform pull requests?
You can run Atlantis as a single binary, a Docker container, or a Kubernetes deployment. For a small team on Ubuntu 24 with Docker, the container path is fastest. Point it at a GitHub or GitLab repo that holds your Terraform modules and environment roots.
Step 1: Deploy the Atlantis server
Create a dedicated VM or container with outbound access to your cloud APIs and inbound HTTPS from your Git host. Store secrets in environment variables—not in the repo.
# docker-compose.yml (minimal example)
services:
atlantis:
image: ghcr.io/runatlantis/atlantis:v0.30.0
ports:
- "4141:4141"
environment:
ATLANTIS_GH_USER: "atlantis-bot"
ATLANTIS_GH_TOKEN: "${ATLANTIS_GH_TOKEN}"
ATLANTIS_GH_WEBHOOK_SECRET: "${ATLANTIS_WEBHOOK_SECRET}"
ATLANTIS_REPO_ALLOWLIST: "github.com/your-org/*"
ATLANTIS_DATA_DIR: "/atlantis-data"
volumes:
- ./atlantis-data:/atlantis-data
Mount a persistent volume for /atlantis-data. Atlantis stores cloned repos and lock files there. Ephemeral containers without a volume lose locks on restart and confuse operators.
Step 2: Register the webhook
In GitHub repo settings, add a webhook pointing to https://atlantis.example.com/events. Subscribe to pull request, issue comment, and push events. Paste the same secret into ATLANTIS_GH_WEBHOOK_SECRET. Without matching secrets, every event returns 401 and plans never trigger.
Step 3: Define projects in atlantis.yaml
Place atlantis.yaml at the repo root. It tells Atlantis which directories are separate Terraform projects and how they relate to Terraform workspaces and environments.
version: 3
automerge: false
parallel_plan: true
parallel_apply: false
projects:
- name: production-vpc
dir: environments/production/vpc
workspace: default
autoplan:
when_modified: ["*.tf", "*.tfvars", "../../modules/**/*.tf"]
enabled: true
apply_requirements: [approved, mergeable]
- name: staging-vpc
dir: environments/staging/vpc
workspace: default
autoplan:
when_modified: ["*.tf", "*.tfvars"]
enabled: true
The apply_requirements array is your governance gate. Require approved so a second engineer must sign off. Require mergeable so conflicting branches cannot apply. On teams where I also manage application deploys with Deployer and GitLab CI, this file plays the same role as a protected branch rule.
Step 4: Wire remote state and provider credentials
Atlantis runs Terraform on the server. Configure the backend the same way you would locally, as described in Terraform remote state on S3 with locking. Use an IAM role, workload identity, or scoped service account attached to the Atlantis host—not long-lived root keys.
# environments/production/vpc/backend.tf
terraform {
backend "s3" {
bucket = "company-terraform-state"
key = "production/vpc/terraform.tfstate"
region = "ap-southeast-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
If you use Terragrunt to keep Terraform DRY, set workflow: terragrunt in atlantis.yaml and install Terragrunt on the Atlantis image. The PR comment flow stays identical; only the underlying command changes.
How does Atlantis compare to Terraform Cloud and GitHub Actions?
Teams evaluating Atlantis pull-request automation for Terraform usually compare three options: self-hosted Atlantis, HashiCorp Terraform Cloud (or HCP Terraform), and custom Terraform CI/CD with GitHub Actions. Each can run plan on PR and apply on merge. The trade-offs are cost, lock-in, and operational burden.
| Criteria | Atlantis (self-hosted) | Terraform Cloud / HCP | GitHub Actions |
|---|---|---|---|
| Hosting | Your VM, K8s, or Docker | HashiCorp SaaS | GitHub-hosted runners |
| Cost model | Server cost only (Rs 3,000–15,000/mo, ~USD 22–110) | Per-seat or run-based pricing | Minutes-based; free tier limits |
| PR comment UX | Native, polished | Native via VCS integration | Custom with actions/github-script |
| State locking | Uses your existing backend | Built-in remote state | Uses your existing backend |
| Policy as code | External (Checkov, OPA, Sentinel via TFC only) | Sentinel (paid tiers) | Bring your own scanner |
| Vendor lock-in | Low — open source | Medium — TFC features | Low — YAML in repo |
| Ops responsibility | You patch, monitor, secure | HashiCorp manages platform | GitHub manages runners |
Pick Atlantis when you already run Terraform with S3 or GCS backends and want PR-native workflows without SaaS per-run fees. Pick Terraform Cloud when you want managed state, Sentinel policies, and private module registry in one bill. Pick GitHub Actions when your Terraform footprint is small and you want everything inside existing CI YAML.
For a broader tool comparison, see Terraform vs Pulumi vs OpenTofu. Atlantis works with all three CLIs because it shells out to whatever binary you install on the server.
What are the best practices for securing Atlantis in production?
Atlantis holds cloud credentials and can modify production infrastructure. Treat the server like a CI controller with root-level cloud access. A misconfigured instance is worse than no automation at all.
Restrict repository access
Set ATLANTIS_REPO_ALLOWLIST to explicit org/repo patterns. Never use a wildcard on public GitHub if the server is internet-facing. Forked PRs from untrusted contributors are a known attack surface—disable autoplan on forks or require approval before planning.
Scope IAM and use short-lived credentials
Attach an IAM role to the EC2 instance or K8s service account. Grant only the actions your modules need. Rotate keys if you must use them. This mirrors how I harden Ubuntu servers for client workloads under Linux system administration engagements: least privilege, no shared root keys, audit logs enabled.
Add policy scanning before apply
Run Checkov to scan Terraform for misconfigurations in a custom workflow step or as a pre-plan hook. Block applies when critical rules fail—public S3 buckets, open security groups, missing encryption. For HashiCorp-only shops, Sentinel policy as code lives inside Terraform Cloud, not native Atlantis, but OPA and Conftest integrate cleanly.
Protect state and secrets
Remote backends must use encryption and locking, as outlined in manage Terraform state safely. Never commit .tfvars with secrets. Inject sensitive values through environment variables referenced in Terraform or through a secrets manager Atlantis reads at runtime. Validate JSON payloads from webhooks—our JSON formatter tool helps debug malformed event bodies during setup.
How do you troubleshoot common Atlantis failures with Terraform?
Most production tickets fall into five buckets. Work through them in order before reinstalling anything.
- Webhook not firing. Check GitHub delivery logs. Confirm the URL, secret, and TLS certificate. A self-signed cert without proper trust breaks silently.
- Plan succeeds locally but fails in Atlantis. Compare Terraform and provider versions. Pin versions in
required_versionandrequired_providersblocks per Terraform provider version pinning guidance. - Project lock stuck after crash. Run
atlantis unlock -p project-nameon the PR. Investigate why the container restarted without graceful shutdown. - Backend access denied. The Atlantis role lacks
s3:GetObjector DynamoDB lock permissions. Fix IAM—not Terraform code. - Drift after apply. Something changed outside Terraform. Schedule regular plans from main and read Terraform drift detection strategies.
Enable debug logging with ATLANTIS_LOG_LEVEL=debug temporarily. Redact tokens before sharing logs. For module errors, reproduce with atlantis plan -p project-name -- -target=module.foo to narrow scope.
On sister sites I maintain with Deployer 7 and GitLab CI—similar to the pipeline behind Notary Kathmandu—the same discipline applies: one change at a time, visible logs, quick rollback path. Atlantis gives Terraform the same operational hygiene.
When should you adopt Atlantis for your Terraform workflow?
Adopt Atlantis pull-request automation for Terraform when:
- Two or more engineers touch the same Terraform repos weekly
- You already use remote state with locking via S3, GCS, or Azure Blob
- PR review is mandatory but plan output is inconsistent or missing
- Terraform Cloud cost or data residency rules push you toward self-hosting
- You need multi-repo, multi-directory monorepo layouts with independent project locks
Skip Atlantis—for now—if you have a single engineer, one environment, and five resources. A Makefile and pre-commit hooks suffice. Scale into automation when review friction costs more than a small VM.
Structure modules first using patterns from Terraform modules for reusable infrastructure. Then add Atlantis. Automating messy roots only speeds up mistakes.
For larger platform work—multi-environment Laravel apps on AWS with Terraform-provisioned VPCs—see how enterprise application development ties application and infrastructure lifecycles together. Atlantis sits at the infrastructure side; your app CI sits beside it, not inside it.
Official Terraform docs at developer.hashicorp.com/terraform cover CLI behaviour Atlantis wraps. Atlantis-specific server flags and server-side repo config are documented at runatlantis.io/docs.
Key Takeaways
- Atlantis automates
terraform planon every PR andapplyonly after explicit approval comments or configured merge rules. - Define projects in
atlantis.yamlwithapply_requirements, autoplan paths, and optional Terragrunt workflows. - Run Atlantis on a hardened host with scoped IAM, repo allowlists, and encrypted remote state—not developer laptops.
- Compare cost and ops burden against Terraform Cloud and GitHub Actions before committing; Atlantis wins on PR UX plus backend flexibility.
- Add Checkov or OPA scanning and drift detection on main to catch misconfigurations before and after apply.
- Pin Terraform and provider versions so Atlantis plans match local runs and CI does not surprise you on merge day.
People Also Ask
Does Atlantis work with GitLab and Bitbucket?
Yes. Atlantis supports GitHub, GitLab, Gitea, and Bitbucket Cloud through VCS-specific environment variables. The PR comment workflow is identical; only webhook setup and token scopes differ. GitLab self-managed instances need outbound access from the Atlantis server to both the GitLab API and your cloud provider.
Can Atlantis run OpenTofu instead of Terraform?
Yes. Set the ATLANTIS_TFE_LOCAL_EXECUTION or custom workflow to call the tofu binary. Many teams migrating under the OpenTofu fork keep Atlantis unchanged and swap the CLI on the server image. Lock files and provider sources must match the binary you execute.
How many repos can one Atlantis server handle?
A single modest VM—2 vCPU, 4 GB RAM—handles dozens of repos with moderate PR volume. Bottlenecks appear when many parallel plans run large modules. Disable parallel_plan or shard across multiple Atlantis instances with repo-based routing if plan queues grow past acceptable wait times.
Is Atlantis free for commercial use?
Atlantis is open source under the Apache 2.0 license. There is no per-run fee. You pay for compute, storage, and engineer time to operate and secure the server. That cost model suits agencies and product teams that already self-host CI controllers.
Ship reviewable infrastructure changes with confidence
Atlantis pull-request automation for Terraform turns opaque infrastructure edits into reviewable, logged, repeatable workflows. Install it on a locked-down host, define projects in atlantis.yaml, connect your existing remote backend, and require approvals before apply. Pair it with policy scanning and drift checks on main. Your future self—and whoever inherits the repo—will thank you on the first avoided outage.
Need help designing Terraform modules, CI pipelines, or production server hardening for a Nepali or global product team? Contact us to discuss your infrastructure and build automation roadmap, or browse the Adventure Third Pole Trek portfolio entry for an example of a Laravel platform backed by disciplined deploy practices.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

