Schema
In Infrahub, the schema is at the center of most things and our goal is to provide as much flexibility as possible to allow users to extend and customize the schema.
Out of the box, Infrahub doesn't have a schema for most things and it's up to users to load a schema that fits their needs. Over time we plan to maintain different schemas for the common types of use cases, but for now, we are providing one example schema to model a basic network with objects like Device, Interface, IPAddress, etc.
Unlike traditional databases that can only have one schema at a time, in Infrahub it is possible to have a different schema per branch. This is possible because the schema itself is stored in the database like any other object.
There are several ways to load a new schema.
To help with the development process of a schema definition file, you can leverage the schemas we publish for validation within your editor
Exploring the Infrahub Schema video
A recording of a livestream that covers:
- What the Infrahub schema actually is
- Why we built it this way (and what we rejected)
- How it compares to other source of truth tools
- Best practices for customizing the schema to your environment
Schema definition
Node, Attributes, Relationships, and Generics
The schema is composed of 4 primary types of objects: Nodes
- that are themselves composed of Attributes
and Relationships
and finally Generics
.
- A
Node
in Infrahub represents aModel
. Nodes are instances of a specific object within your infrastructure. Nodes have attributes that define specific values, such as text or numbers, and relationships that link them to other nodes. - An
Attribute
represents a direct value associated with aNode
like aText
, aNumber
etc ... - A
Relationship
represents a link between 2Node
, aRelationship
can be of cardinalityone
ormany
. - A
Generic
can be used to share attributes and relationships between different types ofNode
s. They can connect multiple types of nodes to the same relationship or define attributes and relationships on a specific list of nodes. Generics are similar to class inheritance in programming languages like Java or Python.
Some namespace like Core
, Infrahub
, Profile
, and Builtin
are reserved and can't be used by users to defined new Nodes and Generics.
In a similar fashion, some attributes name can't be used, like attribute
or relationship
.
Nodes vs. Generics
Use a Node
when you need to represent a concrete object in your infrastructure model with specific attributes and relationships.
Use a Generic
when you want to share common attributes or relationships across multiple node types. This helps to avoid redundancy and ensures consistency across your schema. For example, if you have different types of network interfaces (physical, logical) that share common attributes like name and description, you can define a Generic
interface with these attributes and have the specific interface types inherit from it.
Generic
s can also be used to connect multiple types of Nodes to the same relationship.
A Generic
cannot exist independently; it must be instantiated by at least one Node
.
Two limitations could have an impact on your choice of node vs generic :
- computed attributes can only be used on Nodes, see computed attribute topic for more information.
- Generic's properties are propagated to Nodes only during the first import see the section Inherited properties below.
Field ordering with order weight
The order in which attributes and relationships appear in the Infrahub frontend is controlled by the order_weight
property. Items with lower values appear before those with higher values. When not explicitly specified, Infrahub automatically assigns default values in increments of 1000:
nodes:
- name: Device
namespace: Example
attributes:
- name: hostname # Gets order_weight: 1000
kind: Text
- name: description # Gets order_weight: 2000
kind: Text
optional: true
- name: serial_number # Gets order_weight: 3000
kind: Text
relationships:
- name: location # Gets order_weight: 4000
peer: ExampleLocation
cardinality: one
This automatic assignment ensures predictable field ordering while leaving room for custom positioning. To customize field order, you can specify explicit order_weight
values:
attributes:
- name: asset_tag
kind: Text
order_weight: 100 # Appears first
- name: hostname
kind: Text
order_weight: 200 # Appears second
- name: description
kind: Text
optional: true
order_weight: 9000 # Appears last
Node example
In the example below, the node Person
has 2 attributes (name
and description
) and the node Car
has 1 attribute (model
) and 1 relationship to Person
, identified by owner
.
nodes:
- name: Person
namespace: Example1
attributes:
- name: name
kind: Text
unique: true
- name: description
kind: Text
optional: true
- name: Car
namespace: Example1
attributes:
- name: model
kind: Text
relationships:
- name: owner
peer: Example1Person
optional: false
cardinality: one
kind: Attribute
Node
, Attribute
, and Relationship
are defined by their kind
. While the name and the namespace of the node are up to the creator of the schema, the kinds for the attributes and the relationships are coming from Infrahub. The kind
of an attribute, or a relationship, is important because it defines how each element is represented in GraphQL and the UI.
The kind
of a model is generated by concatenating the namespace
and the name
.
Attribute kinds
Text
: Standard TextNumber
: Standard NumberNumberPool
: Standard Number that creates aCoreNumberPool
resource manager tied to the attributeTextArea
: Long-form Text that can span multiple linesDateTime
: A Date and a TimeDropdown
: A list of choices, each choice can have a color and descriptionEmail
: Email addressPassword
: A Text String that should be obfuscated but which can be read with enough right in the UIHashedPassword
: Similar to Password but it will not be shown in the UI and can't be re-read.URL
: An URL to a website or a resource over HTTPFile
: Path to a file on the filesystemMacAddress
: Mac Address following the format (XX:XX:XX:XX:XX:XX)Color
: An HTML colorBoolean
: Flag that can be either True or FalseBandwidth
: Bandwidth in kbpsIPHost
: IP Address in either IPV4 or IPv6 formatIPNetwork
: IP Network in either IPV4 or IPv6 formatCheckbox
: Duplicate ofBoolean
List
: List of any valueJSON
: Any data structure compatible with JSONAny
: Can be anything
Attribute kinds behavior in the UI
Kind | Display in List View | Display in Detailed View |
---|---|---|
ID | No | Yes |
Text | Yes | Yes |
Number | Yes | Yes |
NumberPool | Yes | Yes |
Boolean | Yes | Yes |
Dropdown | Yes | Yes |
TextArea | No | Yes |
DateTime | No | Yes |
Email | Yes | Yes |
Password | No | Yes |
URL | Yes | Yes |
File | Yes | Yes |
MacAddress | Yes | Yes |
Color | Yes | Yes |
Bandwidth | Yes | Yes |
IPHost | Yes | Yes |
IPNetwork | Yes | Yes |
Checkbox | No | Yes |
List | No | Yes |
JSON | No | Yes |
Any | No | Yes |
Attribute parameters
There are some attribute kinds that allow optional parameters
to be defined to control the behavior of the attribute. Below are the attribute kinds and their accepted parameters.
- Number
- NumberPool
- Text
- TextArea
Parameter | Default |
---|---|
min_value | None |
max_value | None |
excluded_values | None |
Parameter | Default |
---|---|
end_range | 9223372036854775807 |
start_range | 1 |
Parameter | Default |
---|---|
regex | None |
min_length | None |
max_length | None |
Parameter | Default |
---|---|
regex | None |
min_length | None |
max_length | None |
Relationship kinds
Generic
: A flexible relationship with no specific functional significance. It is commonly used when an entity doesn't fit into specialized categories likeComponent
orParent
.Attribute
: A relationship where related entities' attributes appear directly in the detailed view and list views. It's used for linking key information, like statuses or roles.Component
: This relationship indicates that one entity is part of another and appears in a separate tab in the detailed view of a node in the UI. It represents a composition-like relationship where one node is a component of the current node.Parent
: This relationship defines a hierarchical link, with the parent entity often serving as a container or owner of another node. Parent relationships are mandatory and allow filtering in the UI, such as showing all components for a given parent.Group
(system-managed): Defines a relationship where a node (inheriting fromCoreNode
) is a member or subscriber to a group (inheriting fromCoreGroup
). Do not model this in user schemas; it's created/managed by Infrahub. These relationships appear in the "Manage Groups" form and enable organizational concepts fundamental to Infrahub's architecture.Profile
: A special relationship where a node is assigned a profile (inheriting fromCoreProfile
), visible during creation or updates through a "select profile" dropdown.
Relationship kinds behavior in the UI
ID | cardinality | Display in List View | Display in Detailed View | Display in Tab |
---|---|---|---|---|
Generic | one | No | Yes | No |
Generic | many | No | No | Yes |
Attribute | one | Yes | Yes | No |
Attribute | many | Yes | Yes | No |
Component | one | No | Yes | No |
Component | many | No | No | Yes |
Hierarchical Parent | one | Yes | Yes | No |
Hierarchical Children | many | No | No | Yes |
Parent | one | No | Yes | No |
Component and Parent typically belong together:
The Component
relationship is typically paired with the Parent
relationship.
This ensures a strong relationship in both directions, where the parent node can manage its components, and the component refers back to its parent.
Relationships of kind Component
include an implicit on_delete: cascade
. This means that if you delete a node with a Component
relationship, the related nodes connected by this relationship will also be deleted.
Group and Profile are internal relationship:
The Group
and Profile
relationship kinds are internal types and should not be directly used by the user in their schema.
These are automatically handled by the system for managing memberships and configurations.
Relationships of kind Component
will automatically be covered by the template when enabling template generation on a given schema node. See the object-template topic for more information.
To help you understand the relationship types better, here’s an example schema using a real-world model of Car, Person and Wheel.
version: "1.0"
nodes:
- name: Car
namespace: Auto
description: "A vehicle used for transportation."
attributes:
- name: model
kind: Text
description: "The model of the car."
- name: year
kind: Number
description: "The manufacturing year of the car."
- name: license_plate
kind: Text
unique: true
description: "License plate number."
relationships:
- name: owner
peer: AutoPerson
kind: Attribute
cardinality: one
optional: false
- name: wheels
peer: AutoWheel
kind: Component
cardinality: many
- name: Wheel
namespace: Auto
description: "A wheel of the car, a critical component for movement."
attributes:
- name: wheel_size
kind: Number
description: "Size of the wheel in inches."
- name: type
kind: Text
description: "Type of the wheel (e.g., alloy, steel)."
relationships:
# A wheel must belong to a car, hence the Parent relationship is mandatory
- name: car
peer: AutoCar
kind: Parent
cardinality: one
optional: false
- name: Person
namespace: Auto
description: "A person who may own a car."
attributes:
- name: first_name
kind: Text
description: "First name of the person."
- name: last_name
kind: Text
description: "Last name of the person."
- name: driver_license_number
kind: Text
unique: true
description: "Driver's license number."
relationships:
- name: cars
peer: AutoCar
kind: Component
cardinality: many
optional: true
- A
Car
node might have anowner
attribute linking it to aPerson
. This relationship will be visible in the car's detailed view. - A
Wheel
is a component of aCar
, meaning wheels are an essential part of the car. The wheels will be displayed in a separate "Components" tab. - A
Car
can have aProfileCar
selected during its creation or update. The insurance details appear in the form where you can pick or assign a profile for the car.