diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml
new file mode 100644
index 0000000..6e98a0a
--- /dev/null
+++ b/.github/workflows/terraform.yml
@@ -0,0 +1,45 @@
+name: "terraform"
+
+# for security should only run on push to bors branches (staging/trying)
+on:
+  push:
+    branches:
+      - staging
+      - trying
+
+jobs:
+  terraform-deploy:
+    if: github.repository == 'nix-community/infra'
+    runs-on: ubuntu-latest
+    env:
+      SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
+      TF_IN_AUTOMATION: true
+    steps:
+      - uses: actions/checkout@v3
+      - uses: dorny/paths-filter@v2
+        id: changes
+        with:
+          filters: |
+            terraform:
+              - 'terraform/**'
+      - uses: cachix/install-nix-action@v18
+        if: steps.changes.outputs.terraform == 'true'
+        with:
+          extra_nix_config: |
+            experimental-features = nix-command flakes
+            access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
+      - name: init
+        if: steps.changes.outputs.terraform == 'true'
+        run: nix develop -c ./terraform/deploy terraform init -input=false
+      - name: validate
+        if: steps.changes.outputs.terraform == 'true'
+        run: nix develop -c ./terraform/deploy terraform validate
+      - name: fmt
+        if: steps.changes.outputs.terraform == 'true'
+        run: nix develop -c ./terraform/deploy terraform fmt -check
+      - name: plan
+        if: steps.changes.outputs.terraform == 'true' && github.ref == 'refs/heads/trying'
+        run: nix develop -c ./terraform/deploy terraform plan -input=false
+      - name: apply
+        if: steps.changes.outputs.terraform == 'true' && github.ref == 'refs/heads/staging'
+        run: nix develop -c ./terraform/deploy terraform apply -auto-approve -input=false
diff --git a/bors.toml b/bors.toml
index 369554d..8cd6ca1 100644
--- a/bors.toml
+++ b/bors.toml
@@ -3,4 +3,6 @@ status = [
   "ci/hercules/derivations",
   "ci/hercules/effects",
   "ci/hercules/evaluation",
+  # not a required status check
+  "terraform-deploy",
 ]
diff --git a/terraform/.envrc b/terraform/.envrc
deleted file mode 100644
index 074a87c..0000000
--- a/terraform/.envrc
+++ /dev/null
@@ -1,5 +0,0 @@
-source_up
-
-# terraform cloud without the remote execution part
-export TF_FORCE_LOCAL_BACKEND="1";
-eval "$("$direnv" dotenv bash <(sops -d --output-type dotenv secrets.yaml))"
diff --git a/terraform/deploy b/terraform/deploy
index f17ebfd..f989cd8 100755
--- a/terraform/deploy
+++ b/terraform/deploy
@@ -1,5 +1,9 @@
 #!/usr/bin/env bash
 set -euo pipefail
 
-terraform init
-terraform apply
+pushd "$(dirname "$0")" >/dev/null
+
+# terraform cloud without the remote execution part
+TF_FORCE_LOCAL_BACKEND="1" sops exec-env secrets.yaml "${*}"
+
+popd >/dev/null