Dependency Graph
The dependency graph is the backbone of Kyku’s execution ordering. It ensures resources are created, updated, and destroyed in the correct sequence.
GraphBuilder
Section titled “GraphBuilder”The GraphBuilder class in @kykucloud/core scans every resource property for BaseResource instances and builds a Directed Acyclic Graph (DAG).
Edge Detection
Section titled “Edge Detection”// Object reference → creates edgevm.network = myVpc;// Result: Vm → Vpc edge
// Array of objects → creates edgesvm.securityGroups = [sg1, sg2];// Result: Vm → sg1, Vm → sg2 edges
// String reference → NO edgevm.network = "vpc-abc123";// Result: no dependency created (use object references!)| Reference Type | Edge Created? | Example |
|---|---|---|
BaseResource property |
✅ Yes | vm.network = myVpc |
BaseResource[] property |
✅ Yes | vm.securityGroups = [sg1, sg2] |
| String (ID) | ❌ No | vm.network = "vpc-id" |
Tags/labels (Record<string, string>) |
❌ No | tags: { env: "prod" } |
| Output references | ✅ Yes | vm.env.DATABASE_URL = db.outputs.endpoint |
Important: Use object references (not string IDs) to ensure the dependency graph captures all edges.
Level Assignment
Section titled “Level Assignment”Resources are assigned levels via topological sort:
Level 0: Vpc, SshKey (no dependencies)Level 1: SecurityGroup, Subnet (depends on Vpc)Level 2: Vm, Database (depends on Vpc, SG, Subnet)Level 3: LoadBalancer (depends on Vm, Vpc, SG)Resources at the same level execute in parallel. Level N waits for all levels < N to complete.
Cycle Detection
Section titled “Cycle Detection”GraphBuilder.hasCycles() detects circular dependencies and throws a CycleError:
// Bad: circular referencesgA.ingress = [{ sources: [sgB] }];sgB.ingress = [{ sources: [sgA] }];// CycleError: Circular dependency detectedCircuits with TargetGroup ↔ LoadBalancer are avoided by making only one direction reference the other.
Destroy Order
Section titled “Destroy Order”Destroy follows the reverse of creation order. Resources at higher levels are destroyed first:
Destroy order: LoadBalancer → Vm → SecurityGroup → VpcThe destroyOrder array in the CLI must list resources in this reverse order.
Graph Verification
Section titled “Graph Verification”Use kyku graph to inspect and verify resource connectivity:
kyku graph # ASCII tree view with nodes, edges, and levelskyku graph --dot # Graphviz DOT outputkyku graph -c ./my-config.ts # Inspect a specific configVerification Checklist
Section titled “Verification Checklist”| Check | How |
|---|---|
| No dangling references | Every depends on: ID in the tree output refers to a node that appears elsewhere in the graph |
| No orphan resources | Every node has at least one dependency OR at least one dependent (unless standalone like SshKey) |
| Create order correct | Roots (level 0) appear first, leaves appear last |
| Destroy order matches levels | Compare destroyOrder against graph output |
| No unintended cycles | Detected automatically — CycleError thrown at validation time |
| Auto-subnet injection | After injectAutoSubnets(), graph shows synthetic Subnet nodes under each Vpc |
Visual Inspection with –dot
Section titled “Visual Inspection with –dot”kyku graph --dot > graph.dotdot -Tsvg graph.dot > graph.svg # Color-coded SVGdot -Tpng graph.dot > graph.png # PNG for docsDot output assigns distinct shapes and colors per resource type:
Vpc= folder shape, blueVm= box shape, greenSecurityGroup= hexagon, orangeSubnet= ellipse, purpleLoadBalancer= diamond, redDatabase= cylinder, yellow
Auto-Subnet Injection
Section titled “Auto-Subnet Injection”After the user’s resources are collected, the engine injects synthetic Subnet resources for each Vpc with distributeAcrossAzs > 0:
// Vpc with distributeAcrossAzs: 2// Creates 4 synthetic Subnet resources:// vpc-main-subnet-public-0 (level 1, depends on Vpc)// vpc-main-subnet-public-1 (level 1, depends on Vpc)// vpc-main-subnet-private-0 (level 1, depends on Vpc)// vpc-main-subnet-private-1 (level 1, depends on Vpc)These subnets are first-class resources in the graph and state file. VMs are automatically wired to private subnets (or public if they have public SG rules).
Implementation
Section titled “Implementation”class GraphBuilder { // Entry point build(resources: BaseResource[]): Graph
// Edge detection private scanForReferences(resource: BaseResource): string[] private isBaseResource(value: unknown): boolean
// Topological sort private assignLevels(edges: Edge[]): Map<string, number>
// Cycle detection hasCycles(): boolean
// Output toAscii(): string toDot(): string}
interface Graph { nodes: Node[] edges: Edge[] levels: Map<string, number>}
interface Node { id: string type: ResourceType name: string}
interface Edge { from: string // dependent to: string // dependency}