Skip to main content

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:
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

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:
  relationships:
    - name: interfaces
      peer: InfraInterface
      kind: Component
      cardinality: many

Interface:
  relationships:
    - name: device
      peer: InfraDevice
      kind: Parent
      cardinality: one
      optional: false
Device:
  relationships:
    - name: site
      peer: LocationSite
      kind: Attribute
      cardinality: one

Site:
  relationships:
    - name: devices
      peer: InfraDevice
      kind: Attribute
      cardinality: many
Device:
  relationships:
    - name: tags
      peer: BuiltinTag
      kind: Attribute
      cardinality: many

Tag:
  relationships:
    - name: devices
      peer: InfraDevice
      kind: Attribute
      cardinality: 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

Build docs developers (and LLMs) love