Should Application-Specific Terraform Live With the Application Code?

0
0
Asked By MellowCedar42 On

Our team is designing a developer-centric Terraform setup from a greenfield perspective. Each application currently has separate repositories for the backend, frontend, and infrastructure. We are comparing two approaches.

In the first approach, Terraform lives in an environment or infrastructure repository. Reusable modules define application components such as databases, object storage, secrets, and services, while the environment repository composes those modules with shared infrastructure.

In the second approach, application-specific infrastructure is colocated with the application code. For example, the backend repository would publish a Terraform module containing everything the backend needs to run, while accepting shared resources such as a VPC as inputs. The environment repository would provide the shared infrastructure and instantiate the application module.

The main advantage of the first approach is consistency and reuse. The main advantage of the second is that application and infrastructure changes can evolve together in one pull request. This could also make database migrations and other lifecycle-sensitive changes easier to coordinate with application releases.

Our goal is to give development teams end-to-end ownership and let them make most application infrastructure changes without depending on a central platform team. We still want centrally governed Terraform modules to enforce security, compliance, and resource constraints. Projects are relatively independent, although some contain multiple frontends, backends, or microservices. Terraform execution is always performed through CI from the environment repository rather than directly from application repositories.

A possible model would be a layered setup: global infrastructure such as accounts, networking, and connectivity; project-level shared infrastructure; and application-specific infrastructure colocated with each application. How would you design this setup, and what tradeoffs have you encountered around repository structure, state boundaries, reuse, scaling, and database migrations?

4 Answers

Answered By VividHarbor8 On

A layered model is usually the best compromise. Keep global networking, account configuration, shared IAM, and shared clusters in a centrally managed layer. Let each application own the resources specific to its lifecycle, such as queues, buckets, service definitions, application IAM, and dedicated databases.

The important distinction is between reusable building blocks and where they are instantiated. Security-approved modules can remain centrally versioned, while the application repository declares that its service needs a particular bucket or database. That lets developers work in the same change set as the application without giving them permission to bypass platform standards.

One caution is that the environment repository should not become a bottleneck. If it remains the only place where Terraform runs, make sure application changes can be promoted independently and that unrelated applications cannot block one another. Clear state boundaries and automated validation are more important than whether the code is technically in one repository or another.

QuietMaple31 -

That matches our thinking. The environment layer would still own project-wide resources, while each application module would describe only its own resources and consume shared outputs such as the VPC or cluster identifiers.

Answered By OrbitingPine6 On

The application repository pattern works well when the application team owns the service end to end, but it becomes harder to govern as the number of applications grows. With many services, independently maintained Terraform definitions tend to drift: provider versions, database settings, naming conventions, and operational defaults gradually diverge.

A practical design is to keep the application-facing interface stable and put the implementation behind centrally maintained modules. Applications then declare a small, consistent contract while the platform team updates the underlying resources and publishes new module versions. Use separate Terraform state and execution units per application or environment so one team's change cannot lock or break every other deployment.

The scale of the organization matters. A handful of tightly related applications can use a lot of coupling safely. Dozens of services usually need stronger central conventions, automated upgrades, policy checks, and possibly a service that standardizes Terraform execution.

AmberField27 -

For our projects, the unit of ownership is usually the project rather than each individual microservice. A project might have a frontend and backend, with only a few larger projects growing into many services, so the expected sprawl is more limited.

Answered By SilverKite19 On

Co-locating application code and application infrastructure makes changes easier to review and revert. Adding a new queue, storage resource, or database can be part of the same change as the feature that consumes it, instead of requiring synchronized changes across two repositories.

That does not mean the application repository should contain raw, unrestricted Terraform. Keep shared infrastructure in a separate layer, expose its outputs through a well-defined mechanism, and provide approved modules for common resources. The application module should have a narrow scope and should not manage resources shared by unrelated applications.

I would also consider allowing a service team to use the most suitable deployment technology for its application-specific resources, provided the ownership and policy boundaries remain clear. Terraform can manage shared infrastructure while a service uses another supported tool for tightly coupled application deployment needs.

CleverBirch54 -

Separate deployment stages for shared infrastructure and application infrastructure seem useful here. They make ownership clearer and avoid requiring every application deployment to understand or modify the project's shared resources.

Answered By CopperWren73 On

Database migrations should be owned by the application release process, not by the infrastructure layer. Infrastructure automation can create or alter the database instance, but it should not decide when a schema migration runs.

A common sequence is to provision or update required infrastructure, run a backward-compatible migration, deploy the new application version, and then complete any cleanup migration later. The exact order depends on the migration strategy, but the application team should control it because it understands compatibility between the schema and code.

Whichever repository triggers Terraform, preserve that ownership boundary. A central pipeline can orchestrate the steps, but it should not hide migration logic inside the environment repository.

Related Questions

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.