Overview
Relationships connect nodes together to form a graph-based data model. They define how entities relate to each other, enabling powerful queries and data navigation in Infrahub.
Relationship Structure
Every relationship has these core properties:
relationships :
- name : site # Relationship name
peer : LocationSite # Target node kind
cardinality : one # one or many
kind : Attribute # Relationship type
optional : false # Required or optional
identifier : site__devices # Unique identifier (optional)
order_weight : 1000 # Display order
Cardinality Types
One-to-One
A node can be related to at most one instance of the peer:
relationships :
- name : primary_address
peer : IpamIPAddress
cardinality : one
kind : Attribute
optional : true
Example : A device has one primary IP address.
One-to-Many
A node can be related to multiple instances of the peer:
relationships :
- name : interfaces
peer : InfraInterface
cardinality : many
kind : Component
optional : true
Example : A device has many interfaces.
Many-to-Many
Both sides can have multiple relationships (defined by cardinality on each side):
relationships :
- name : tags
peer : BuiltinTag
cardinality : many
kind : Attribute
optional : true
Example : Devices can have many tags, and tags can be applied to many devices.
Relationship Kinds
Infrahub supports four relationship kinds, each with different semantics:
Attribute Relationship
Standard relationship between independent entities:
relationships :
- name : site
peer : LocationSite
kind : Attribute
cardinality : one
optional : false
Characteristics:
Default relationship type
Both entities exist independently
Deleting one doesn’t affect the other
Bidirectional by default
Use case : Device belongs to a Site, but both exist independently.
Component Relationship
Parent-child relationship where children are owned by the parent:
relationships :
- name : interfaces
peer : InfraInterface
kind : Component
cardinality : many
optional : true
identifier : device__interface
Characteristics:
Strong ownership relationship
Deleting parent deletes all components
Components typically can’t exist without parent
Used for composition patterns
Use case : Device owns interfaces; deleting the device deletes its interfaces.
Parent Relationship
Explicit parent-child where child must reference a parent:
relationships :
- name : device
peer : InfraDevice
kind : Parent
cardinality : one
optional : false
Characteristics:
Child must have a parent (usually optional: false)
Parent can have many children
Deleting parent may delete children (depends on configuration)
Enforces hierarchy
Use case : Interface must belong to a Device.
Generic Relationship
Flexible relationship for inheritance and polymorphic associations:
relationships :
- name : members
peer : InfraInterface
kind : Generic
cardinality : many
optional : true
Characteristics:
Most flexible relationship type
Can connect to multiple node types
Used with generics and inheritance
Use case : LAG interface members can be various interface types.
Relationship Direction
Relationships have directional properties:
Outbound (Default)
Inbound
Bidirectional
relationships :
- name : site
peer : LocationSite
direction : outbound # or omit (default)
cardinality : one
Relationship Identifiers
Identifiers create unique names for bidirectional relationships:
# On Device
relationships :
- name : interfaces
peer : InfraInterface
identifier : device__interface
cardinality : many
kind : Component
# On Interface
relationships :
- name : device
peer : InfraDevice
identifier : device__interface # Same identifier links them
cardinality : one
kind : Parent
Using the same identifier on both sides creates a bidirectional relationship where updates to one side reflect on the other.
Common Relationship Patterns
Parent-Child (Composition)
# Parent: Device
nodes :
- name : Device
namespace : Infra
relationships :
- name : interfaces
peer : InfraInterface
identifier : device__interface
cardinality : many
kind : Component
# Child: Interface
- name : Interface
namespace : Infra
relationships :
- name : device
peer : InfraDevice
identifier : device__interface
cardinality : one
kind : Parent
optional : false
Hierarchical Relationships
For tree structures:
generics :
- name : Generic
namespace : Location
hierarchical : true
nodes :
- name : Country
namespace : Location
inherit_from :
- LocationGeneric
parent : "LocationContinent"
children : "LocationSite"
Self-Referencing
Node relates to itself:
relationships :
- name : parent_group
peer : InfraGroup
cardinality : one
optional : true
- name : child_groups
peer : InfraGroup
cardinality : many
optional : true
Peer-to-Peer
Symmetric relationships:
relationships :
- name : connected_endpoint
peer : InfraEndpoint
identifier : connected__endpoint
cardinality : one
kind : Attribute
optional : true
Advanced Relationship Features
Common Parent Constraint
Ensure related objects share the same parent:
relationships :
- name : lag
peer : InfraLagInterface
cardinality : one
optional : true
kind : Attribute
common_parent : device # LAG must be on same device
Validation : When assigning a LAG to an interface, Infrahub verifies both are on the same device.
Hierarchical Relationships
For querying tree structures:
relationships :
- name : parent
peer : LocationGeneric
hierarchical : location_hierarchy
cardinality : one
optional : true
Enables : Recursive queries up/down the hierarchy.
Relationship Filters
Add constraints to relationships:
relationships :
- name : active_interfaces
peer : InfraInterface
cardinality : many
filters :
- name : status
value : "active"
Relationship Examples
Network Infrastructure
Device-Site Relationship
Interface-Device Relationship
IP-Interface Relationship
nodes :
- name : Device
namespace : Infra
relationships :
- name : site
peer : LocationSite
identifier : site__devices
cardinality : one
kind : Attribute
optional : false
order_weight : 1
- name : Site
namespace : Location
relationships :
- name : devices
peer : InfraDevice
identifier : site__devices
cardinality : many
kind : Component
Organizational Structure
nodes :
- name : Organization
namespace : Org
relationships :
- name : devices
peer : InfraDevice
cardinality : many
kind : Attribute
optional : true
- name : sites
peer : LocationSite
cardinality : many
kind : Attribute
optional : true
- name : contacts
peer : OrgContact
cardinality : many
kind : Component
Circuit Connectivity
nodes :
- name : Circuit
namespace : Infra
relationships :
- name : provider
peer : OrganizationProvider
identifier : circuit__provider
cardinality : one
kind : Attribute
optional : false
- name : endpoints
peer : InfraCircuitEndpoint
cardinality : many
kind : Component
- name : bgp_sessions
peer : InfraBGPSession
cardinality : many
kind : Component
- name : CircuitEndpoint
namespace : Infra
relationships :
- name : site
peer : LocationSite
identifier : site__circuit_endpoints
cardinality : one
kind : Attribute
- name : circuit
peer : InfraCircuit
cardinality : one
kind : Parent
optional : false
Working with Relationships
from infrahub_sdk import InfrahubClient
client = InfrahubClient( address = "http://localhost:8000" )
# Create site
site = await client.create(
kind = "LocationSite" ,
name = "NYC-DC1"
)
await site.save()
# Create device with relationship to site
device = await client.create(
kind = "InfraDevice" ,
name = "router-01" ,
type = "router" ,
site = site # Assign relationship
)
await device.save()
Querying Relationships
# Get device with related site
device = await client.get(
kind = "InfraDevice" ,
name__value = "router-01" ,
include = [ "site" ] # Include related objects
)
print ( f "Device: { device.name.value } " )
print ( f "Site: { device.site.node.name.value } " )
Updating Relationships
# Get objects
device = await client.get( kind = "InfraDevice" , name__value = "router-01" )
new_site = await client.get( kind = "LocationSite" , name__value = "LAX-DC1" )
# Update relationship
device.site = new_site
await device.save()
Traversing Relationships
# Get site with all devices
site = await client.get(
kind = "LocationSite" ,
name__value = "NYC-DC1" ,
include = [ "devices" ]
)
for device in site.devices:
print ( f "Device: { device.node.name.value } " )
Best Practices
Use Meaningful Names Choose relationship names that clearly describe the connection
Define Both Sides Create bidirectional relationships for easier navigation
Set Appropriate Cardinality Use one for single relationships, many for collections
Choose the Right Kind Use Component for ownership, Parent for hierarchy, Attribute for associations
Use Identifiers Link bidirectional relationships with matching identifiers
Consider Deletion Understand cascade behavior for Component and Parent relationships
Common Patterns Summary
Device-Interface (Parent owns Components)
Device :
relationships :
- name : interfaces
peer : InfraInterface
kind : Component
cardinality : many
Interface :
relationships :
- name : device
peer : InfraDevice
kind : Parent
cardinality : one
optional : false
Device-Site (Entity belongs to Location)
Device :
relationships :
- name : site
peer : LocationSite
kind : Attribute
cardinality : one
Site :
relationships :
- name : devices
peer : InfraDevice
kind : Attribute
cardinality : many
Device-Tags (Many-to-Many)
hierarchical : true
Continent :
parent : ""
children : "LocationCountry"
Country :
parent : "LocationContinent"
children : "LocationSite"
Site :
parent : "LocationCountry"
children : ""
Next Steps
Create Schema Learn how to define complete schemas with relationships
Schema Validation Understand relationship constraints and validation
Object Management Work with related objects in Infrahub
GraphQL Queries Query relationships via GraphQL API