Modeling a project's infrastructure as a graph
A flat list of resources can't tell a load-bearing database from one nobody uses anymore. A dependency graph can, by walking it from the project's entry points.
- Project
- CNP: Cloud-Native Platform
- Published
- September 24, 2026
- Reading time
- 2 min read
On CNP, teams ask for the parts of their stack that aren't containers, like a managed database, and the platform provisions them with access scoped to their project. I owned that layer end to end: the model for what a team asks for, the provisioning behind it, and the API and front end teams use to ask. This post is about the change to it I'd point to first, how a project describes its infrastructure.
Claims
What a team writes is a claim: a short description of what it needs, a database of some size for some project, with nothing about how that's built. Crossplane turns the claim into the actual cloud resources behind it, and those are the platform's problem, not the team's.
Most of the work was keeping that boundary simple enough that nobody needs to understand the resources on the right to get the left side correct. That boundary is also where the next problem showed up.
What a flat list can't say
A project used to be a flat list of claims. That's fine for a handful of resources, but a list has no way to say which resources depend on which, so it can't tell a database that three services use from one that nothing has touched since a migration. Both are one more line, and both cost money every month. Nobody deletes a database they aren't sure about, so unused resources just pile up.
A project as a graph
I proposed the alternative: a project as a dependency graph. Each resource declares what it depends on, and the project's entry points, the things the team actually runs, are the roots.
Walking such a graph from the roots would reach everything that's in use, and anything the walk doesn't reach is dead weight or a mistake, either way worth showing to the team. It also catches what a per-resource check would miss. An old database's backup bucket is still depended on by something, the old database, so asking "does anything use this?" says yes. Only reachability from the roots shows that the whole branch is dead.
What exists today is the interface, where a team describes its project as that graph. The part that stores the graph and walks it isn't built yet.
One repo per resource
Beyond my own part I worked with the team on how changes reach the cluster. Each resource gets its own git repo, and ArgoCD reconciles each repo onto the cluster as its own application, under one parent application whose only job is managing the others (the app-of-apps pattern).
So a change to one resource syncs that resource and nothing else, and every resource has its own history that can be reviewed or reverted on its own, instead of one shared repo where every team's changes are tangled together.