Module Inputs and Outputs
Variables are a module's inputs; outputs are how it returns values to the caller.
Modules communicate through a clear contract: input variables flow in, outputs flow back out. Resources inside a module are private — the caller can only see declared outputs.
The pattern
- The module declares
variableblocks (its inputs). - The caller passes values in the
moduleblock. - The module declares
outputblocks (its results). - The caller reads them as
module.NAME.OUTPUT.
This encapsulation keeps modules composable and easy to reason about.
Example
# Inside modules/web-service/outputs.tf
output "url" {
value = "https://${aws_lb.this.dns_name}"
description = "Public URL of the service"
}
# In the root module
module "web" {
source = "./modules/web-service"
instance_type = "t3.small"
}
output "service_url" {
value = module.web.url
}When to use it
- A VPC module outputs its vpc_id and subnet_ids so caller configurations can reference them when creating EC2 instances or load balancers.
- A database module outputs the endpoint, port, and database name so an ECS task definition module can consume them as environment variables.
- A caller uses module.network.vpc_id to feed the VPC module's output directly into a security group resource without storing the value in a variable.
More examples
Module outputs definition
Defines the outputs a VPC module exposes: the VPC ID and all private subnet IDs as a list.
# modules/vpc/outputs.tf
output "vpc_id" {
description = "ID of the created VPC"
value = aws_vpc.this.id
}
output "private_subnet_ids" {
description = "List of private subnet IDs"
value = aws_subnet.private[*].id
}Caller references module outputs
Shows the caller using module.name.output_name syntax to consume both the vpc_id and private_subnet_ids from the network module.
module "network" {
source = "./modules/vpc"
name = "prod"
cidr_block = "10.0.0.0/16"
}
resource "aws_security_group" "app" {
vpc_id = module.network.vpc_id # consume module output
name = "app-sg"
}
resource "aws_lb" "app" {
subnets = module.network.private_subnet_ids
}Pass module output to another module
Chains module outputs as inputs to another module, creating a dependency graph without any hard-coded resource IDs.
module "network" {
source = "./modules/vpc"
name = "prod"
}
module "database" {
source = "./modules/rds"
vpc_id = module.network.vpc_id
subnet_ids = module.network.private_subnet_ids
allowed_sg_id = module.app.security_group_id
}
Discussion