Home Posts Terraform mono repo vs multi repo
Terraform

Terraform mono repo vs multi repo

Terraform structure is not folder organization. It defines how infrastructure is owned, governed, deployed, and scaled across teams and evironments. The goal is to make operational boundaries clear:…

Jul 3, 2026 8 min read maki96milosavljevic@gmail.com

Terraform structure is not folder organization. It defines how infrastructure is owned, governed, deployed, and scaled across teams and evironments.

The goal is to make operational boundaries clear: who owns which part of infrastructure, where is the state stored, how changes move from dev to prod, what the blast radius could look like, who the rollback could look like, etc.

On simpler projects it is usually clear: a single repo with remote state and that’s it. The common discussion though is connected to more complex projects and whether you should use single or multi repo setup. There are few things which might influence decision and setup.

In this blog I will try to help you with deciding whether you should use Terraform mono repo vs multi repo setup.

State boundaries

In Terraform, the root module is the deployment boundary. It is the directory where Terraform is initialized, planned, and applied.

Each root module should have its own remote state. For small systems, one root module can be enough. In large infrastructure setups, state is typically separated by lifecycle, ownership, and blast radius so that teams can deploy safely and independently. For example you want to split big chunks of the same project into different state file.

Example:

shared state:
  VPC
  KMS keys
  certificates
  common IAM
  shared networking

frontend state:
  S3 static hosting
  CloudFront
  WAF
  DNS records

service state:
  Lambda
  API Gateway
  SQS
  CloudWatch alarms
  • Splitting state this way avoids locking the entire platform for every small change.
  • It also reduces the impact of mistakes.
  • If you change frontend infrastructure, you do not want to plan or risk unrelated shared networking resources.
Mono repo

A mono repo keeps modules, stacks, and environment configuration together. Although within mono repo you still can have one or more Terraform entrypoints.

This is example of single entrypoint which is Terraform root module with additional modules and environment files.

infra/
  main.tf
  variables.tf
  outputs.tf
  providers.tf
  backend.tf
  vpc.tf
  s3.tf
  lambda.tf
  cloudfront.tf

  modules/
    s3/
      main.tf
      variables.tf
      outputs.tf

    lambda/
      main.tf
      variables.tf
      outputs.tf

    cloudfront/
      main.tf
      variables.tf
      outputs.tf

  envs/
    dev.tfvars
    qa.tfvars
    prod.tfvars

You can run this project from root module:

terraform init
terraform plan -var-file=envs/dev.tfvars
terraform apply -var-file=envs/dev.tfvars

This is common when one team or single person owns most of the infrastructure, or when the infrastructure pieces are tightly connected or let’s say if the project is rather simple.
Note that if you are, for whatever reason, using one cloud account for multiple environments you need to have state per each env.

The main advantage is consistency. Shared modules are easy to update, global refactors are easier, and reviewers can compare environments in one place.

The downside is that access control and CI/CD can become more complex if many teams work in the same repository. Also since you Terraform project in this case is single deployable unit if you have issues with some parts of the project entire project is blocked.

Mono repo with multiple entrypoints

If the mono repo has 3 Terraform entrypoints, then you usually do not put main.tf, variables.tf, backend.tf and outputs.tf directly in root Terrafrom module. Instead each stack/service directory is the actual Terraform root module.

infra/
  modules/
    s3/
    lambda/
    cloudfront/

  stacks/
    shared/
      main.tf
      variables.tf
      outputs.tf
      backend.tf
      dev.tfvars
      prod.tfvars

    frontend/
      main.tf
      variables.tf
      outputs.tf
      backend.tf
      dev.tfvars
      prod.tfvars

    notification/
      main.tf
      variables.tf
      outputs.tf
      backend.tf
      dev.tfvars
      prod.tfvars

In this setup, Terraform is executed from each stack directory:

cd infra/stacks/frontend
terraform init
terraform plan -var-file=dev.tfvars

This one is also achievable by utilizing Terraform workspaces.
The point is: mono repo does not necessarily mean a single Terraform root module.

This approach is to keep all Terraform code in one repository, but split the infrastructure into multiple stacks. Each stack is its own root module and deployment unit, with its own Terraform configuration and remote state.

Simple mono repo usually works well when:

  • One team owns the whole infrastructure
  • The project is small or medium-sized
  • Infrastructure components share the same lifecycle
  • The blast radius of one Terraform state is acceptable
  • You want the simplest possible setup
  • Environments differ mostly by variable values

Mono repo with multiple stacks usually works well when:

  • One repository is still preferred, but infrastructure needs clearer boundaries
  • Different parts of the platform have different lifecycles
  • You want separate state files for shared, frontend, notification, etc.
  • Some stacks should be deployed independently
  • You want to reduce the blast radius of each Terraform apply
  • Teams or reviewers need clearer ownership per stack
Multi Repo

A multi-repo model gives each service or team its own infrastructure repository.

Example:

platform-infra/
  shared networking
  identity
  security baseline

frontend-infra/
  frontend-specific AWS resources

notification-infra/
  notification service resources

A multi-repo setup separates infrastructure by ownership boundary. Shared infrastructure may live in a platform repository, while each application or service has its own infrastructure repository.

This works well when teams need to move independently. Each team can own its deployment lifecycle, review process, permissions, and CI/CD pipeline.

For example, a larger company may keep global management configuration, such as organization-level permissions, policies, billing setup, and security baselines, in a dedicated platform repository with restricted access. Application teams can then manage their own service-specific infrastructure in separate repositories.

The tradeoff is consistency. Since infrastructure code is spread across multiple repositories, teams need stronger standards for module usage, naming conventions, validation, policies, and interfaces between stacks. Documentation and long-term maintenance also become more important.

Multi repo usually works well when:

  • Different teams own different services
  • Services have different release cycles
  • Access control should be separated
  • Each service/team needs its own CI/CD pipeline
  • Infrastructure boundaries are clearly defined
Remote state works in both models

Terraform remote state is independent of repository structure.

A mono repo can have multiple state files. A multi-repo setup can also have multiple state files. The repository model decides where the code lives; the state design decides the deployment boundaries.

One stack can read outputs from another stack if it knows the backend location and has permission to access it.

data "terraform_remote_state" "shared" {
  backend = "s3"

  config = {
    bucket = "shared-tfstate"
    key    = "shared/terraform.tfstate"
    region = "eu-central-1"
  }
}

For example, a frontend stack can read VPC or DNS outputs from a shared platform stack, even if they are stored in different repositories. What is important is that state file exists in S3 bucket, that you know correct bucket, key and region, and IAM role/user which runs Terraform has permissions to read that state file.

Conclusion

There is no single best Terraform structure. The right choice depends on project complexity, team ownership, security requirements, environment isolation, and deployment strategy.

Use a mono repo when the infrastructure is mostly owned by one team or person and the project is still simple enough to review and deploy from one place.

Use a mono repo with multiple stacks when you still want one repository, but need separate root modules, separate state files, smaller deployment boundaries and isolation between services to reduce blast radius. Also with people working with this setup you can do parallel work as stacks can be developed and shipped independently.

Use multi repo when different teams own different services, release independently, need separate permissions, require their own CI/CD pipelines, want shared (baseline) services isolated, etc.

Author

maki96milosavljevic@gmail.com

Practical notes about AWS, Terraform, DevOps, automation, and building systems that are easier to operate.