Terraform modules for reusable infrastructure

Ryan Nakamura Feb 2026
2 tabs
# Using the module

module "api_service" {
  source = "./modules/ecs_service"

  service_name       = "api"
  cluster_id         = aws_ecs_cluster.main.id
  cluster_name       = aws_ecs_cluster.main.name
  vpc_id             = module.vpc.vpc_id
  subnet_ids         = module.vpc.private_subnet_ids
  image_repository   = "123456789.dkr.ecr.us-east-1.amazonaws.com/api"
  image_tag          = var.api_image_tag
  container_port     = 3000
  health_check_path  = "/health"
  cpu                = 512
  memory             = 1024
  desired_count      = 3
  min_count          = 2
  max_count          = 10
  aws_region         = var.aws_region
  execution_role_arn = aws_iam_role.ecs_execution.arn
  task_role_arn      = aws_iam_role.api_task.arn
  alb_security_group_id = aws_security_group.alb.id
  log_retention_days = 30

  environment_variables = {
    NODE_ENV  = "production"
    REDIS_URL = aws_elasticache_cluster.main.cache_nodes[0].address
  }

  secrets = {
    DATABASE_URL = aws_secretsmanager_secret.db_url.arn
    JWT_SECRET   = aws_secretsmanager_secret.jwt.arn
  }
}

module "worker_service" {
  source = "./modules/ecs_service"

  service_name       = "worker"
  cluster_id         = aws_ecs_cluster.main.id
  cluster_name       = aws_ecs_cluster.main.name
  vpc_id             = module.vpc.vpc_id
  subnet_ids         = module.vpc.private_subnet_ids
  image_repository   = "123456789.dkr.ecr.us-east-1.amazonaws.com/worker"
  image_tag          = var.worker_image_tag
  container_port     = 8080
  health_check_path  = "/health"
  cpu                = 1024
  memory             = 2048
  desired_count      = 2
  min_count          = 1
  max_count          = 8
  aws_region         = var.aws_region
  execution_role_arn = aws_iam_role.ecs_execution.arn
  task_role_arn      = aws_iam_role.worker_task.arn
  alb_security_group_id = aws_security_group.alb.id
  log_retention_days = 14

  environment_variables = {
    NODE_ENV    = "production"
    QUEUE_NAME  = "default"
    CONCURRENCY = "5"
  }

  secrets = {
    DATABASE_URL = aws_secretsmanager_secret.db_url.arn
    API_KEY      = aws_secretsmanager_secret.api_key.arn
  }
}
2 files · hcl Explain with highlit

Terraform modules encapsulate related resources into reusable, composable packages. A module is simply a directory with .tf files. The root module calls child modules with the module block. Input variable blocks parameterize modules. output blocks expose values to the caller. Modules can be sourced from local paths, Git repositories, or the Terraform Registry. Version constraints pin module versions. Module composition builds complex infrastructure from simple building blocks. for_each and count create multiple module instances. locals compute intermediate values. Well-designed modules have clear interfaces, sensible defaults, and comprehensive documentation. The DRY principle applies—extract common patterns into shared modules.