🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Atlantis Review 2026: Terraform PR Automation Worth It?

Honest hands-on review of Atlantis — the open-source tool that runs terraform plan and apply from GitHub and GitLab PRs. Setup, atlantis.yaml config, security concerns, comparison with Spacelift and Terraform Cloud, and a clear verdict.

DevOpsBoys5 min read
Share:Tweet

Terraform workflows break down at team scale. Engineers terraform apply from their laptops with different versions, different state file versions, and no audit trail. Atlantis fixes this by making GitHub/GitLab PRs the only way to run Terraform — plan on PR open, apply on PR merge.

I've run Atlantis in production for 18 months across three different teams. Here's an honest review.

What Atlantis Does

Atlantis is a self-hosted webhook server. You point your GitHub/GitLab repo at it, and it reacts to PR events:

  1. PR opened or new commit pushed → Atlantis runs terraform plan → posts the plan output as a PR comment
  2. Someone comments atlantis apply → Atlantis runs terraform apply → posts output as a PR comment
  3. PR is locked until the apply succeeds or the lock is released

The entire team sees the plan before anything changes. No more "I applied from my laptop and something went wrong."

Setup

Docker (simplest for testing)

bash
docker run -p 4141:4141 \
  -e ATLANTIS_GH_USER=my-bot-user \
  -e ATLANTIS_GH_TOKEN=ghp_... \
  -e ATLANTIS_GH_WEBHOOK_SECRET=my-webhook-secret \
  -e ATLANTIS_REPO_ALLOWLIST="github.com/myorg/*" \
  -v $(pwd)/atlantis-data:/atlantis \
  ghcr.io/runatlantis/atlantis:v0.32.0 server

Point your GitHub repo webhook at https://your-atlantis-url.com/events with content type application/json.

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: atlantis
  namespace: atlantis
spec:
  replicas: 1  # IMPORTANT: always 1 replica, Atlantis has no distributed locking
  selector:
    matchLabels:
      app: atlantis
  template:
    metadata:
      labels:
        app: atlantis
    spec:
      serviceAccountName: atlantis
      containers:
      - name: atlantis
        image: ghcr.io/runatlantis/atlantis:v0.32.0
        args:
        - server
        - --atlantis-url=https://atlantis.mycompany.com
        - --gh-user=$(GH_USER)
        - --gh-token=$(GH_TOKEN)
        - --gh-webhook-secret=$(WEBHOOK_SECRET)
        - --repo-allowlist=github.com/myorg/*
        - --write-git-creds
        env:
        - name: GH_USER
          valueFrom:
            secretKeyRef:
              name: atlantis-secrets
              key: gh-user
        - name: GH_TOKEN
          valueFrom:
            secretKeyRef:
              name: atlantis-secrets
              key: gh-token
        - name: WEBHOOK_SECRET
          valueFrom:
            secretKeyRef:
              name: atlantis-secrets
              key: webhook-secret
        volumeMounts:
        - name: atlantis-data
          mountPath: /atlantis
      volumes:
      - name: atlantis-data
        persistentVolumeClaim:
          claimName: atlantis-pvc

Note the replicas: 1. Atlantis uses a file-based locking mechanism. Running multiple replicas causes split-brain lock issues. This is a hard architectural constraint.

atlantis.yaml Configuration

Place this in your repo root:

yaml
version: 3
automerge: false
delete_source_branch_on_merge: false
parallel_plan: true
parallel_apply: false
 
projects:
- name: vpc
  dir: terraform/vpc
  workspace: production
  terraform_version: v1.9.0
  autoplan:
    when_modified: ["*.tf", "*.tfvars", "../modules/**/*.tf"]
    enabled: true
  apply_requirements:
    - approved
    - mergeable
 
- name: eks-cluster
  dir: terraform/eks
  workspace: production
  terraform_version: v1.9.0
  autoplan:
    when_modified: ["*.tf", "*.tfvars", "../modules/eks/**/*.tf"]
    enabled: true
  apply_requirements:
    - approved
    - mergeable
    - undiverged
 
- name: rds
  dir: terraform/rds
  workspace: production
  terraform_version: v1.9.0
  apply_requirements:
    - approved
    - mergeable

apply_requirements is critical. approved means at least one reviewer must approve the PR before atlantis apply can run. undiverged means the branch must be up to date with main — prevents applying an outdated plan.

How Plan Output Looks in PRs

When you open a PR modifying Terraform files, Atlantis posts a comment like:

Ran Plan for dir: terraform/eks workspace: production

Changes to Outputs:
  ~ cluster_endpoint = "https://old-endpoint.eks.amazonaws.com" -> (known after apply)

Terraform will perform the following actions:

  # module.eks.aws_eks_node_group.workers will be updated in-place
  ~ resource "aws_eks_node_group" "workers" {
      ~ scaling_config {
          ~ desired_size = 3 -> 5
            max_size     = 10
            min_size     = 1
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

To apply this plan, comment: atlantis apply -d terraform/eks -w production

The team sees exactly what will change. Reviewers can ask questions before approving. This is the core value proposition.

Locking Mechanism

When Atlantis runs a plan, it locks that Terraform workspace. No one else can plan or apply that workspace until:

  • The PR is merged (lock released after apply)
  • The PR is closed/abandoned
  • Someone comments atlantis unlock

This prevents concurrent modifications to the same state file — a real problem in active teams. The lock is visible in the Atlantis web UI and as PR comments.

Security Concerns

This is where Atlantis requires careful thought.

Blast radius is large. Atlantis typically runs with IAM permissions to create/delete any infrastructure in your account. A compromised Atlantis instance means full AWS access.

Mitigations:

  • Run Atlantis in its own isolated namespace with network policies
  • Use IRSA (IAM Roles for Service Accounts) with tightly scoped permissions per project
  • Set apply_requirements: [approved] — never allow self-approved applies
  • Enable branch protection: allowed_override_list in atlantis.yaml to restrict who can override requirements
  • Audit logs: all Atlantis actions are logged and posted to PRs — full audit trail

PR-based attack vector. If an attacker opens a PR with a malicious Terraform provider or null_resource with arbitrary command execution, Atlantis will run it during plan. Mitigations:

yaml
# atlantis.yaml - restrict allowed providers
allowed_regexp_prefixes:
  - "hashicorp/"
  - "aws/"

Also consider: Atlantis Enterprise (paid) has policy-as-code integration via OPA. Open-source Atlantis relies on code review for this.

Comparison: Atlantis vs Spacelift vs Terraform Cloud

FeatureAtlantisSpaceliftTerraform Cloud
CostFree (self-hosted)$500+/month$20/user/month
HostingYou manageSaaSSaaS
Drift detectionNoYesYes
Policy enforcementManual/OPA pluginNative OPASentinel
Multi-cloudYesYesYes
VCS supportGitHub, GitLab, BitbucketAll majorGitHub, GitLab, Bitbucket
State storageBring your own backendBuilt-inBuilt-in
Audit logPR commentsFull UI + APIFull UI + API
Private module registryNoYesYes
Setup complexityMediumLowLow
Replicas1 onlyN/AN/A

Who Should Use Atlantis

Good fit:

  • Teams of 3-15 engineers running Terraform on GitHub/GitLab
  • Organizations that want to keep everything self-hosted for compliance/cost reasons
  • Teams already comfortable operating Kubernetes (since you'll be running Atlantis on K8s)
  • Environments where a simple PR-based workflow is sufficient

Not a good fit:

  • Large enterprises needing Sentinel policy enforcement, drift detection, and cost estimation built-in → use Terraform Cloud or Spacelift
  • Teams without Kubernetes operational experience → the SaaS options reduce operational burden significantly
  • Solo developers or very small teams → just use GitHub Actions with manual state management

Verdict: 7.5/10

Atlantis is excellent at the one thing it does: making PR comments the interface for Terraform. The plan-on-PR workflow is a genuine improvement over ad-hoc laptop applies, and the locking mechanism prevents a class of team coordination problems.

The limitations are real: single replica constraint, no drift detection, limited policy enforcement, and the operational overhead of self-hosting. For teams that outgrow Atlantis, migrating to Spacelift is straightforward since both use similar PR-based workflows.

Bottom line: If you're a startup or mid-size team self-hosting your infra and want collaborative Terraform without paying $500+/month for enterprise tooling, Atlantis is the right choice. Deploy it on Kubernetes, set apply_requirements: [approved, mergeable], and enforce branch protection. You'll spend one afternoon setting it up and get years of value from it.

For enterprise teams with compliance requirements or teams that want drift detection and cost estimates in PRs without building it themselves, pay for Terraform Cloud or Spacelift — the operational savings justify the cost.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments