Bare Terraform + GitHub Actions (module per tenant)

Tags: Substrate · Modeling · Automation · Self-host Substrate: bare Terraform + GitHub Actions

The same default-shipping integration as the one-file-per-tenant variant, with a different repo structure and stronger per-tenant isolation. Use this pattern when isolation between tenants matters more than DRY config: each tenant gets its own Terraform module and state file, so a problem with one tenant can't affect another.

What you'll see

OnboardTenant runs placement, creates a Tenant entity in provisioning, then the pull-request trigger commits a whole directory — tenants/acme/{main.tf,backend.tf,versions.tf} — in one PR. On merge, the GitHub Actions workflow uses git diff to detect only the new tenants/acme/ directory and runs terraform init && terraform apply for that tenant alone. Terrantula transitions the tenant to active when the merge webhook fires.

One file per tenantModule per tenant
Per-tenant stateShared (one big state file)Isolated (one state file per tenant)
Version driftAll tenants on the same module versionEach tenant can pin its own version
Failure blast radiusA bad apply can affect all tenantsA bad apply affects one tenant
PR commitsOne file: tenants/<id>.tfvars.jsonA directory: tenants/<id>/{main.tf,backend.tf,versions.tf}

The Terrantula blueprint is structurally identical between the two patterns — only the pull-request trigger's files array changes. The workflow applies; Terrantula never runs terraform apply.

Try it

cd examples/bare-tf-gh-actions-module-per-tenant
./run-demo.sh

Without a real GitHub token the PR step fails with a 401 (expected); placement, entity creation, and lifecycle still validate. With a real token:

export GITHUB_TOKEN=ghp_...
export GITHUB_TARGET_REPO=my-org/my-terraform-repo
./run-demo.sh

To wire your repo, drop in .github/workflows/terrantula-tf-dispatch.yml (it applies only the changed tenant directory per merge) and add the required secrets:

SecretValue
AWS_DEPLOY_ROLE_ARNThe IAM role to assume for applies (trusts GitHub OIDC).
AWS_REGIONThe AWS region for Terraform operations.

Key files

FileWhat it is
blueprint.yamlThe Terrantula schema + OnboardTenant action.
cluster-seed.yamlTwo TenantCluster entities for the demo's cell.
run-demo.shThe end-to-end demo runner.
terraform/main.tfThe shared module each tenant directory calls.
tenants/.gitkeepPlaceholder; per-tenant directories are added by Terrantula PRs.
.github/workflows/terrantula-tf-dispatch.ymlThe workflow that applies only changed tenant dirs (with OIDC).

View on GitHub

examples/bare-tf-gh-actions-module-per-tenant