Skip to main content

Single-target queries

When writing GraphQL queries for transformations, generators, artifacts, and computed attributes, it's critical to use a single-target query pattern to ensure proper tracking by the system.

What is a single-target query?​

A single-target query is a GraphQL query that targets a unique node using a unique attribute or ID. This pattern enables Infrahub to identify exactly which objects are affected by a change, allowing it to selectively trigger the necessary action instead of everything.

Why is this important?​

Without single-target queries, Infrahub cannot determine which specific actions need to be triggered when data changes. This can lead to excessive processing that significantly impacts performance.

Real-world impact: In one production scenario, a proposed change pipeline generated 600 artifact regenerations when only 5 actually required execution. Properly using single-target queries resolved this issue.

Requirements for a valid single-target query​

For a query to be recognized as single-target, it must meet all of these criteria:

  1. Filter on a unique identifier: Use either id or a unique attribute like name__value
  2. Use a required variable: The filter must use a required variable, for example, $name: String!. A literal value is also valid but limits the query to a single fixed object
  3. Use exact match filters: Use singular filters, for example, name__value: $name, not list filters, for example, name__values: $name

Valid single-target query examples​

Using a unique attribute with required variable:

query DeviceConfig($device_name: String!) {
InfraDevice(name__value: $device_name) {
edges {
node {
id
name {
value
}
interfaces {
edges {
node {
name {
value
}
}
}
}
}
}
}
}

Using ID with required variable:

query DeviceById($device_id: String!) {
InfraDevice(ids: [$device_id]) {
edges {
node {
id
name {
value
}
}
}
}
}

Invalid query examples (will cause excessive artifact generation)​

Missing filter (queries all objects):

query AllDevices {
InfraDevice {
edges {
node {
id
name {
value
}
}
}
}
}

Using optional variable:

query DeviceConfig($device_name: String) { # NOT required (no !)
InfraDevice(name__value: $device_name) {
edges {
node {
id
}
}
}
}

Using list filter instead of exact match:

query DeviceConfig($device_name: String!) {
InfraDevice(name__values: $device_name) { # name__values instead of name__value
edges {
node {
id
}
}
}
}

Filtering on non-unique attribute:

query DevicesByRole($role: String!) {
InfraDevice(role__value: $role) { # role is not unique
edges {
node {
id
}
}
}
}

Part of the query is not unique:

query DeviceConfig($device_name: String!) {
InfraDevice(name__value: $device_name) {
edges {
node {
id
name {
value
}
}
}
}
BuiltinTag { # This part is not unique
edges {
node {
name {
value
}
}
}
}
}

Ensuring your query is single-target​

There is currently no automated way to verify that a query is single-target. The best way to verify is to review the query and ensure it meets all the criteria outlined above.

When loaded into the system, Infrahub will analyze the query and determine if it is single-target or not. If it is not single-target, Infrahub will log a warning.

It's planned to add more integrated checks in the future to streamline the development process and ensure that queries are correctly structured directly during development.

When single-target queries are required​

Single-target queries are required for:

When single-target queries are NOT required​

You do not need single-target queries for:

  • Ad-hoc queries via the GraphQL interface or API
  • Reporting queries that intentionally fetch multiple objects
  • Dashboard queries for UI components
  • Bulk data exports

In these cases, you can freely query multiple objects without unique filters.