If your Bicep project has grown from a “single file” into a small ecosystem of parameters, modules, and outputs—welcome to the club. I also got tired of “parsing dependencies by eye” in the code. That’s why I wrote PSBicepGraph—a PowerShell module that builds a semantic graph from your .bicep
files and provides proper tools for analysis and visualization.
What is it and why
PSBicepGraph:
- walks through the entry point
main.bicep
, recursively picking up imported modules; - extracts semantic dependencies between parameters, variables, resources, modules, outputs, etc.;
- builds a bidirectional graph (
PsBidirectionalGraph
); - provides a starting point for exports: GraphViz/MSAGL graphs, Design Structure Matrix (DSM), clustering.
Under the hood—my PSGraph module, a thin wrapper around QuickGraph/QuikGraph with utilities for export and visualization (including Vega).
Current PSBicepGraph version: v1.1.0-beta. The module is published in the PowerShell Gallery.
Installation
Install-Module -Name PSBicepGraph -Repository PSGallery -Scope CurrentUser
Install-Module -Name PSGraph -Repository PSGallery -Scope CurrentUser
Import-Module PSBicepGraph
Import-Module PSGraph
How it works (short version)
Semantic extraction. New-BicepSemanticGraph
registers Bicep services, resolves the path, collects all .bicep files, compiles, and traverses the semantic model with a custom DependencyCollectorVisitor
, mapping each declaration to what it references.
Graph construction. Based on the dependency map, a PsBidirectionalGraph
is created—vertices (declarations) and edges (A→B, where A depends on B).
Integration with PSGraph. Then—export the graph as you like: graph image, interactive HTML tree, or DSM for large projects.
Quick start
Let’s create a simple storage.bicep and build a graph:
param location string = resourceGroup().location
var storageName = 'st${uniqueString(resourceGroup().id)}'
resource stg 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageName
location: location
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
}
output accountId string = stg.id
# 1) Build the semantic graph:
$graph = New-BicepSemanticGraph -Path ./storage.bicep
# 2) Export to HTML (MSAGL):
Export-Graph -Graph $graph -Format MSAGL_MDS -Path $Env:TEMP/storage.html
Start-Process $Env:TEMP/storage.html
For a multi-module project:
$graph = New-BicepSemanticGraph -Path ./main.bicep
$dsm = New-DSM -Graph $graph
$ret = Start-DSMClustering -Dsm $dsm # Classic or Graph
Export-DSM -Result $ret -Format VEGA_HTML -Path $Env:TEMP/dsm.html
Start-Process $Env:TEMP/dsm.html
A couple of examples
Let’s look at the avm
module as an example.
You can get its Force Directed
visualization like this. It does look a bit messy, though.
$graph = New-BicepSemanticGraph -Path "./bicep-registry-modules/avm/res/key-vault/vault/main.bicep"
Export-Graph -Graph $graph -Format Vega_ForceDirected -Path $outFile
You can look at it from another angle—build a tree with a virtual
root. The -UseVirtualTreeRoot
parameter adds a virtual root if the graph happens to have more than one root, for visualization.
$graph = New-BicepSemanticGraph -Path "./bicep-registry-modules/avm/res/key-vault/vault/main.bicep"
$visual = Export-Graph -Graph $graph -Format Vega_TreeLayout -UseVirtualTreeRoot
What is DSM and why is it useful
Design Structure Matrix is a square dependency matrix: rows and columns are the same set of entities; a mark at (i, j) means “row i depends on column j”.
In PSBicepGraph/PSGraph
, the convention is: row = consumer, column = provider; edge A→B becomes a filled cell (A, B). This compactly shows cycles, layers, and module “coupling”. Clustering groups mutually dependent nodes and hints where to draw boundaries. (DSM algorithms are still in progress—but you can already try them.)
For key vault
, unfortunately, it doesn’t fit the layout. So as an example, let’s look at another one, from avm/res/web/serverfarm
$graph = New-BicepSemanticGraph -Path "./bicep-registry-modules/avm/res/web/serverfarm/main.bicep"
$dsm1 = New-DSM -graph $graph
$ret1 = Start-DSMClustering -Dsm $dsm1 -ClusteringAlgorithm Classic
$visual = Export-DSM -Result $ret1 -Format VEGA_JSON
Horizontally, you see “depends on” dependencies, for example, appServicePlan: Resource
depends on a bunch of parameters. Vertically, on the contrary, “depends on me”—various outputs and other resources depend on the same appServicePlan: Resource
.
Links
Repository PSBicepGraph (dev). There you’ll find the README with installation, examples, and screenshots. Module PSGraph - export, DSM, Vega.
P.S. If you’ve ever tried to explain a complex Bicep project with “look, here’s a var, here’s a module, and here’s an output,” you know how painful it is. Now, instead of a 30-minute standup—one picture. And you can argue based on facts, not interpretations.
Would love your feedback :D