Building a library of reusable Terraform modules is a common platform engineering goal. In practice, many modules go unused. Here is what separates the modules teams adopt from the ones they ignore.
The Modules That Work
The networking module. A module that creates a Virtual Cloud Network with public and private subnets, route tables, security lists, and a NAT gateway tends to get adopted quickly because it replaces hundreds of lines of Terraform with a short module invocation. The value is obvious and immediate.
The managed Kubernetes module. A module that provisions a managed Kubernetes cluster with node pools, RBAC, and monitoring integration gets adopted because getting the cloud-specific settings right from scratch requires deep knowledge that most engineers do not have.
The Modules That Fail
The "everything" module. A module that provisions an entire application stack (database, queues, compute, networking) rarely gets used because every team's stack is slightly different. When a module has dozens of input variables, teams spend more time reading its documentation than they would spend writing the Terraform themselves.
The logging module. A module that configures logging with sensible defaults often gets ignored because teams have already set up logging manually and do not want to import existing state.
What Makes a Module Adoptable
- It replaces genuine complexity. If the module saves a trivial amount of code, nobody cares. If it encodes tribal knowledge and replaces significant boilerplate, everyone cares.
- It has few required variables. Every variable is a decision the user has to make. Minimize decisions.
- It works with
terraform planon the first try. If a team has to debug the module before they can use it, they will write their own. - It is versioned. Pin module versions in Terraform. Breaking changes in shared modules break every team simultaneously.