Modules

Stategraph records the module hierarchy of your Terraform states, the resources and instances in each module, and module usage across states. A Terraform module is a reusable container for multiple resources. See the modules in the console under Inventory > Modules, list them with the API, or query them with SQL.

List modules with the API

To get STATE_ID, see Instances.

curl "http://localhost:8080/api/v1/states/$STATE_ID/modules" \
  -H "Authorization: Bearer $STATEGRAPH_API_KEY"

Response:

{
  "results": [
    {
      "name": "module.vpc",
      "instance_count": 25,
      "resource_count": 10
    },
    {
      "name": "module.vpc.module.subnets",
      "instance_count": 12,
      "resource_count": 4
    }
  ]
}

Module properties

Property Description
name Full module path, such as module.vpc.module.private_subnets
instance_count Total resource instances in the module
resource_count Resources (resource blocks, or distinct resource addresses) in the module

Module paths

Module paths follow the Terraform module hierarchy:

rootmodule path is null
  • module.vpc
    • module.subnets
    • module.nat
  • module.eks
    • module.node_groups
  • module.rds
The root module has a null module path.
module.vpc, module.eks, and module.rds are in the root module.
module.subnets and module.nat are nested in module.vpc, and module.node_groups is nested in module.eks.

In SQL, the module path is in resources.module.

Root module resources (not in any module):

SELECT *
FROM resources
WHERE module IS NULL

Resources in module.vpc:

SELECT *
FROM resources
WHERE module = 'module.vpc'

Module analysis

Resources per module

SELECT module, count(*) as resources
FROM resources
WHERE module IS NOT NULL
GROUP BY module
ORDER BY module

Types per module

SELECT module, type, count(*) as type_count
FROM resources
WHERE module IS NOT NULL
GROUP BY module, type
ORDER BY module, type

Top-level modules

List all modules. A top-level module has no nested module. segment:

SELECT module, count(*) as resources
FROM resources
WHERE module IS NOT NULL
GROUP BY module
ORDER BY module

Nested module depth

List the module paths. Each module. segment in a path is one level of nesting:

SELECT module
FROM resources
WHERE module IS NOT NULL
GROUP BY module
ORDER BY module

Module usage patterns

Find duplicate module usage

Count the states that use each module. count(DISTINCT ...) is not supported, so the CTE first keeps one row for each module and state:

WITH module_states AS (
  SELECT module, state_id
  FROM resources
  WHERE module IS NOT NULL
  GROUP BY module, state_id
)
SELECT module, count(*) AS states_using
FROM module_states
GROUP BY module
ORDER BY module

Module resource distribution

MQL does not support CASE, so count root and module resources with two queries.

Resources in the root module:

SELECT count(*) AS resources
FROM resources
WHERE module IS NULL

Resources inside modules:

SELECT count(*) AS resources
FROM resources
WHERE module IS NOT NULL

Resources by module type

SELECT module, type, count(*) as type_count
FROM resources
WHERE module = 'module.vpc'
GROUP BY module, type
ORDER BY type

Common module patterns

VPC module resources

SELECT type, count(*) as type_count
FROM resources
WHERE module = 'module.vpc'
GROUP BY type
ORDER BY type

EKS/Kubernetes modules

SELECT module, type, count(*) as type_count
FROM resources
WHERE module = 'module.eks'
GROUP BY module, type
ORDER BY module, type

Database modules

SELECT module, type, count(*) as type_count
FROM resources
WHERE module = 'module.rds'
GROUP BY module, type
ORDER BY module, type

Best practices

  • Use clear module names, one purpose per module, and shallow nesting (fewer than 3 levels).
  • Track module versions in source control.
  • Monitor instance counts over time, watch for module sprawl, and review cross-module dependencies.
  • Put infrastructure (VPC, EKS, RDS) in modules, app resources in the root or in app modules, and common patterns in shared modules.

Module vs root resources

Compare the resource counts of the root module and of modules.

Resources in the root module:

SELECT count(*) AS resources
FROM resources
WHERE module IS NULL

Resources inside modules:

SELECT count(*) AS resources
FROM resources
WHERE module IS NOT NULL

Next steps