infrahub.rs: a graphql client for infrahub in rust

Mon, 09 Feb 2026 00:00:00 +0000
network automation, tooling, release

talk to infrahub from rust, with typed graphql operations
cargo add infrahub

completing the trio alongside netbox.rs and nautobot.rs: infrahub.rs, a rust client for infrahub.

for those unfamiliar: infrahub is an infrastructure data management platform by opsmill. where netbox and nautobot expose rest apis generated from openapi specs, infrahub is built around graphql. it also has built-in version control for your data—branches, diffs, merges. that makes it interesting for workflows where infrastructure state needs the same rigor as code, and provides a first class alternative to things such as the branching plugin for netbox.

structure

unlike netbox.rs and nautobot.rs, which each provide three crates (openapi bindings, ergonomic client, cli), infrahub.rs takes a two-tier approach:

infrahub: the base crate handling graphql communication, authentication, pagination, and branch routing. this stays stable across schema changes.

infrahub-codegen: a code generator that reads your infrahub graphql schema and produces typed, topic-grouped helpers. since every infrahub deployment can have a different schema, generating the client from your specific instance makes more sense than shipping a static one. it also means that the crate is more lightweight, but less ready “out of the box”.

quick start

from rust:

use infrahub::{Client, ClientConfig};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Data {
    #[serde(rename = "InfrahubInfo")]
    info: InfrahubInfo,
}

#[derive(Debug, Deserialize)]
struct InfrahubInfo {
    deployment_id: String,
    version: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ClientConfig::new("http://infrahub.example.com:8000", "your-api-token");
    let client = Client::new(config)?;

    let response = client
        .execute::<Data>(
            "query { InfrahubInfo { deployment_id version } }",
            None,
            None,
        )
        .await?;

    println!("deployment: {}", response.info.deployment_id);
    Ok(())
}

branch-aware queries are a first-class concept—pass a branch name and the client routes to the right graphql endpoint:

let response = client
    .execute::<Data>(query, None, Some("feature-branch"))
    .await?;

generating typed clients

for anything beyond ad-hoc queries, you’ll want to generate a typed client from your schema:

# fetch the schema from a running instance
./scripts/update_schema.sh http://localhost:8000 your-token

# generate typed helpers
cargo run --bin infrahub-codegen -- --schema schema/schema.graphql --out generated/

this gives you functions grouped by topic instead of hand-writing graphql strings everywhere.

what’s next

like netbox.rs and nautobot.rs, this client exists to support alembic, the larger dcim/ipam convergence tool i’m building¹. having a consistent rust interface to all three platforms is the foundation for multi-backend infrastructure synchronization.

1. announcement for that one will follow once the pieces are in place.↩︎