Skip to main content

Nodes & attributes

A Node is the fundamental unit of the schema — it represents a concrete object in your infrastructure model such as a device, interface, or IP address. Nodes are composed of Attributes (direct values) and Relationships (links to other nodes). This page covers how to define nodes and attributes, what kinds are available, and how to configure identifiers, constraints, and display.

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.

Generics can also be used to connect multiple types of Nodes to the same relationship.

Instantiation Requirement

A Generic cannot exist independently; it must be instantiated by at least one Node.

See Generics & inheritance for a full guide on generics.

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.

info

The kind of a model is generated by concatenating the namespace and the name.

Attribute kinds

  • Text: Standard Text
  • Number: Standard Number
  • NumberPool: Standard Number that creates a CoreNumberPool Resource Manager tied to the attribute
  • TextArea: Long-form Text that can span multiple lines
  • DateTime: A Date and a Time
  • Dropdown: A list of choices, each choice can have a color and description
  • Email: Email address
  • Password: A Text String that should be obfuscated but which can be read with enough right in the UI
  • HashedPassword: 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 HTTP
  • File: Path to a file on the filesystem
  • MacAddress: Mac Address following the format (XX:XX:XX:XX:XX:XX)
  • Color: An HTML color
  • Boolean: Flag that can be either True or False
  • Bandwidth: Bandwidth in kbps
  • IPHost: IP Address in either IPV4 or IPv6 format
  • IPNetwork: IP Network in either IPV4 or IPv6 format
  • Checkbox: Duplicate of Boolean
  • List: List of any value
  • JSON: Any data structure compatible with JSON
  • Any: Can be anything
Attribute kinds behavior in the UI
KindDisplay in List ViewDisplay in Detailed View
IDNoYes
TextYesYes
NumberYesYes
NumberPoolYesYes
BooleanYesYes
DropdownYesYes
TextAreaNoYes
DateTimeNoYes
EmailYesYes
PasswordNoYes
URLYesYes
FileYesYes
MacAddressYesYes
ColorYesYes
BandwidthYesYes
IPHostYesYes
IPNetworkYesYes
CheckboxNoYes
ListNoYes
JSONNoYes
AnyNoYes

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.

ParameterDefault
min_valueNone
max_valueNone
excluded_valuesNone

Uniqueness constraints

More complex uniqueness constraints, composed of multiple attributes and/or relationships, can be defined at the Node or Generic level with the property uniqueness_constraints. It's possible to define multiple uniqueness constraints and each of them will be evaluated individually.

In the example below, the node schema ExampleCar, ["owner", "model__value"] guarantees that a car will be unique based on the owner and the model of the car.

uniqueness_constraints can be composed of a list of N number of attributes or relationships of cardinality one:

  • For an attribute, the valid format is <attributename>__value. Currently only value is supported but in the future, the plan is to allow additional metadata to be used as well.
  • For a relationship, only the name of the relationship should be provided <relationshipname>. Only relationships of cardinality one are supported and the relationship must be mandatory.
nodes:
- name: Person
namespace: Example
attributes:
- name: name
kind: Text
unique: true
- name: Car
namespace: Example
uniqueness_constraints:
- ["owner", "model__value"]
attributes:
- name: model
kind: Text
relationships:
- name: owner
peer: ExamplePerson
optional: false
cardinality: one

Optimizing uniqueness constraints

When defining uniqueness constraints, the order of the elements in each constraint array can significantly impact performance. The uniqueness checker processes constraints from left to right, so listing the most selective elements first can dramatically improve performance.

How It Works

The uniqueness checker runs Cypher queries to validate constraints. When elements are ordered from most to least selective, the database can quickly eliminate non-matching candidates earlier in the query execution.

For example, consider an IP address model with a uniqueness constraint:

uniqueness_constraints:
- ["ip_namespace", "address__value"]

If many IP addresses share the same namespace but few share the same address value, this constraint would require checking all nodes with the same namespace before filtering by address. A more efficient ordering would be:

uniqueness_constraints:
- ["address__value", "ip_namespace"]

This allows the system to first filter by the more selective address value, resulting in fewer nodes to check against the namespace constraint.

Best Practice

Order uniqueness constraint elements from most selective (returning fewer matches) to least selective (returning more matches) to optimize database query performance.

Display label

The display_label property allows you to define a custom label for nodes in the Infrahub UI. This label is used in various parts of the interface, such as list views and detail views, to provide a more user-friendly representation of the node.

See the topic dedicated to display labels./display_label

Human-friendly identifier (hfid)

In addition to the internal ID automatically generated for each object (UUID), Infrahub provides a way to define a set of fields that will constitute a human-friendly identifier (HFID).

Use Case

The hfid is meant to be used to reference objects uniquely across systems, or even before an object has been created in Infrahub. Having a human-friendly way to identify an object is very important to build robust data synchronization between systems and to provide true idempotent scripts.

In the network industry:

  • The hfid of a device could be its name: atl1-edge01
  • The hfid of an interface could be the combination of the name of the device and the name of the interface: (atl1-edge01, Ethernet1)

In the example below, each ExamplePerson, will have a hfid composed of his/her lastname and firstname.

human_friendly_id can be composed of N number of attributes or relationships of cardinality one:

  • For an attribute, the valid format is <attributename>__value. Currently only value is supported but in the future, the plan is to allow additional metadata to be used as well.
  • For a relationship, the name of the relationship and the name of a unique attribute must be provided <relationshipname>__<attributename>__value. Only relationships of cardinality one are supported and the relationship must be mandatory.
nodes:
- name: Person
namespace: Example
human_friendly_id: ["lastname__value", "firstname__value"]
attributes:
- name: firstname
kind: Text
- name: lastname
kind: Text
info

If a human_friendly_id is defined on a node but no uniqueness_constraints are present, a uniqueness constraint matching the human_friendly_id will be automatically created.

If at least one attribute is marked as unique, and human_friendly_id hasn't been defined, human_friendly_id will be automatically created.

hfid support in GraphQL

hfid can be used as an alternative to id in most places in GraphQL, including:

  • Update Mutation
  • Upsert Mutation
  • Delete Mutation
  • Related Node in all Mutations

At the node (or generic) level, three attributes control how a model appears in the frontend sidebar menu:

  • include_in_menu — Boolean to indicate if a given model should be displayed in the menu or not. By default, all models will be displayed directly under Objects in the frontend.
  • menu_placement — Makes it possible to create a nested structure within the menu to display a given model under another one.
  • icon — Indicates which icon should be displayed next to the model in the menu. Any icon from the Material Design Icons library can be used. The full identifier of the icon must be used, for example mdi:domain.

For detailed guidance on structuring the menu and worked examples, see Menu customization.

Field ordering

The order_weight property controls the position of attributes and relationships in the frontend. Lower values appear first; Infrahub assigns defaults in increments of 1000 when order_weight is not specified.

Full order weight reference./order-weight

Reserved namespaces and attribute names

Some namespaces like Core, Infrahub, Profile, and Builtin are reserved and can't be used by users to define new Nodes and Generics.

In a similar fashion, some attribute names can't be used, like attribute or relationship.