> ## Documentation Index
> Fetch the complete documentation index at: https://docs.helix-db.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Querying

> For the complete documentation index optimized for AI agents, see [llms.txt](/llms.txt).

Helix Cloud exposes a single query surface over HTTP. Every query — whether a
deep graph traversal, a vector search, a bulk write, or all three at once — is
expressed in the same composable DSL and executes as one serializable
transaction. Queries are authored once in TypeScript, Rust, Go, or Python (or by hand as
JSON) and sent to the runtime as **dynamic** requests — the request body
carries the query itself, so there is no separate deployment step. The
[Querying Guide](/database/querying-guide/overview) walks the DSL end-to-end;
this page covers how a dynamic query looks on the wire.

## Installing the SDKs

The TypeScript, Rust, Go, and Python examples below are built with the Helix SDKs. Install the one for
your language to follow along — all four emit the same dynamic query JSON.

<CodeGroup>
  ```bash TypeScript theme={"languages":{"custom":["languages/helixql.json"]}}
  npm install @helix-db/helix-db
  ```

  ```bash Rust theme={"languages":{"custom":["languages/helixql.json"]}}
  cargo add helix-db
  ```

  ```bash Go theme={"languages":{"custom":["languages/helixql.json"]}}
  go get github.com/helixdb/helix-db/sdks/go
  ```

  ```bash Python theme={"languages":{"custom":["languages/helixql.json"]}}
  pip install 'git+https://github.com/HelixDB/helix-db.git#subdirectory=sdks/python'
  ```
</CodeGroup>

For the full project layout and generator setup, see
[TypeScript Project Setup](/database/typescript-project-setup),
[Rust Project Setup](/database/rust-project-setup),
[Go Project Setup](/database/go-project-setup), and
[Python Project Setup](/database/python-project-setup).

## Dynamic queries

A dynamic query is sent inline: the request body carries the JSON AST for the
query plus a small envelope that names the request kind, an optional query name,
and any runtime parameters. There is no deployment step — the query travels with
the request, so the same DSL that builds it also produces the body you POST.

The example below counts every `User` node. The TypeScript, Rust, Go, and Python tabs are
builder front-ends that produce the same JSON envelope; pick whichever your
codebase already speaks. The JSON tab shows the resulting envelope verbatim — if
you want to skip the DSL and POST hand-written JSON, this is the body you send.

<CodeGroup>
  ```ts TypeScript theme={"languages":{"custom":["languages/helixql.json"]}}
  import { g, readBatch } from "@helix-db/helix-db";

  const countUsers = readBatch()
    .varAs("user_count", g().nWithLabel("User").count())
    .returning(["user_count"]);

  // The request to POST to /v1/query.
  const request = countUsers.toDynamicRequest({ queryName: "count_users" });
  ```

  ```rust Rust theme={"languages":{"custom":["languages/helixql.json"]}}
  use helix_db::dsl::prelude::*;

  #[register]
  pub fn count_users() -> ReadBatch {
      read_batch()
          .var_as("user_count", g().n_with_label("User").count())
          .returning(["user_count"])
  }

  // Calling the registered fn returns the request to POST to /v1/query.
  let request = count_users();
  ```

  ```go Go theme={"languages":{"custom":["languages/helixql.json"]}}
  import helix "github.com/helixdb/helix-db/sdks/go"

  func CountUsers() helix.Request {
  	return helix.ReadQuery("count_users").
  		VarAs("user_count", helix.G().NWithLabel("User").Count()).
  		Returning("user_count")
  }
  ```

  ```python Python theme={"languages":{"custom":["languages/helixql.json"]}}
  from helixdb import g, read_batch

  count_users = (
      read_batch()
      .var_as("user_count", g().n_with_label("User").count())
      .returning(["user_count"])
  )

  # The request to POST to /v1/query.
  request = count_users.to_dynamic_request(query_name="count_users")
  ```

  ```json envelope theme={"languages":{"custom":["languages/helixql.json"]}}
  {
    "request_type": "read",
    "query_name": "count_users",
    "query": {
      "queries": [
        {
          "Query": {
            "name": "user_count",
            "steps": [
              { "NWhere": { "Eq": ["$label", { "String": "User" }] } },
              "Count"
            ],
            "condition": null
          }
        }
      ],
      "returns": ["user_count"]
    }
  }
  ```
</CodeGroup>

Sending that envelope is one POST to `/v1/query`. The response is a JSON
object keyed by the names from `.returning([...])`.

`query_name` is optional metadata for gateway logs and diagnostics. Use the exact
field `query_name` (not `name` or `queryName`); it defaults to `__dynamic__` when
missing or `null`, and blank strings are rejected.

<CodeGroup>
  ```ts TypeScript theme={"languages":{"custom":["languages/helixql.json"]}}
  import { Client } from "@helix-db/helix-db";

  const client = new Client("https://helix.example.com");

  // Builds the envelope and POSTs it to /v1/query.
  const response = await client
    .query<{ user_count: number }>()
    .dynamic(request) // from .toDynamicRequest() above
    .send();

  const { user_count } = response;
  ```

  ```rust Rust theme={"languages":{"custom":["languages/helixql.json"]}}
  use helix_db::Client;

  let client = Client::new(Some("https://helix.example.com"))?;

  // Builds the envelope and POSTs it to /v1/query.
  let response: serde_json::Value = client
      .query()
      .dynamic(count_users())
      .send()
      .await?;

  let user_count = &response["user_count"];
  ```

  ```go Go theme={"languages":{"custom":["languages/helixql.json"]}}
  import helix "github.com/helixdb/helix-db/sdks/go"

  client, err := helix.NewClient("https://helix.example.com")
  if err != nil {
  	return err
  }

  var response struct {
  	UserCount int64 `json:"user_count"`
  }
  if err := client.Exec(ctx, CountUsers(), &response); err != nil {
  	return err
  }

  userCount := response.UserCount
  ```

  ```python Python theme={"languages":{"custom":["languages/helixql.json"]}}
  from helixdb import Client

  client = Client("https://helix.example.com")

  # Builds the envelope and POSTs it to /v1/query.
  response = client.query().dynamic(request).send()
  user_count = response["user_count"]
  ```

  ```bash curl theme={"languages":{"custom":["languages/helixql.json"]}}
  curl -sS -X POST https://helix.example.com/v1/query \
    -H "content-type: application/json" \
    --data-raw '{
      "request_type": "read",
      "query_name": "count_users",
      "query": {
        "queries": [
          {
            "Query": {
              "name": "user_count",
              "steps": [
                { "NWhere": { "Eq": ["$label", { "String": "User" }] } },
                "Count"
              ],
              "condition": null
            }
          }
        ],
        "returns": ["user_count"]
      }
    }'
  ```
</CodeGroup>

For larger envelopes, write the JSON to a file and use `curl --data-binary
@file.json` — the inline `--data-raw` form gets unwieldy past a few steps.

For parameters, bundles, and the typed `queries.call.*` helpers, see
[Parameters & bundles](/database/querying-guide/parameters-bundles).

## Running queries with the client

The SDKs ship a `Client` so you don't have to assemble requests by hand. The
client owns the connection details (URL and, on Helix Cloud, the API key) and
posts dynamic requests to `/v1/query`.

<CodeGroup>
  ```ts TypeScript theme={"languages":{"custom":["languages/helixql.json"]}}
  import { Client, HelixError } from "@helix-db/helix-db";

  const client = new Client("https://helix.example.com")
    .withApiKey("hx_secret"); // Authorization: Bearer hx_secret

  try {
    const response = await client
      .query<{ user_count: number }>()
      .warmOnly() // X-Helix-Warm: true — pre-populate caches, discard the result
      .writerOnly() // X-Helix-Require-Writer: true — force the writer node
      .shouldAwaitDurability(true) // X-Helix-Await-Durable: true
      .dynamic(request)
      .send();
  } catch (error) {
    if (error instanceof HelixError && error.kind === "Remote") {
      console.error(error.details); // server-side error body
    }
  }

  // Deployed named routes (POST /v1/query/{name}) use `.stored(name)`.
  await client.query().body({ username: "alice" }).stored("user_by_username").send();
  ```

  ```rust Rust theme={"languages":{"custom":["languages/helixql.json"]}}
  use helix_db::{Client, HelixError};

  let client = Client::new(Some("https://helix.example.com"))?
      .with_api_key(Some("hx_secret")); // Authorization: Bearer hx_secret

  let response: serde_json::Value = client
      .query()
      .warm_only() // X-Helix-Warm: true
      .writer_only() // X-Helix-Require-Writer: true
      .should_await_durability(true) // X-Helix-Await-Durable: true
      .dynamic(count_users())
      .send()
      .await?;

  // Deployed named routes (POST /v1/query/{name}) use `.stored(name)`.
  let _: serde_json::Value = client
      .query()
      .body(&serde_json::json!({ "username": "alice" }))?
      .stored("user_by_username".to_string())
      .send()
      .await?;
  ```

  ```go Go theme={"languages":{"custom":["languages/helixql.json"]}}
  import helix "github.com/helixdb/helix-db/sdks/go"

  client, err := helix.NewClient("https://helix.example.com", helix.WithAPIKey("hx_secret"))
  if err != nil {
  	return err
  }

  var response map[string]any
  err = client.Exec(ctx, CountUsers(), &response,
  	helix.WarmOnly(),
  	helix.WriterOnly(),
  	helix.AwaitDurability(true),
  )
  if err != nil {
  	return err
  }
  ```

  ```python Python theme={"languages":{"custom":["languages/helixql.json"]}}
  from helixdb import Client, HelixError

  client = Client("https://helix.example.com", api_key="hx_secret")

  try:
      response = (
          client
          .query()
          .warm_only()
          .writer_only()
          .should_await_durability(True)
          .dynamic(request)
          .send()
      )
  except HelixError as error:
      if error.kind == "Remote":
          print(error.details)
      raise

  # Deployed named routes (POST /v1/query/{name}) use .stored(name).
  client.query().body({"username": "alice"}).stored("user_by_username").send()
  ```
</CodeGroup>

`send()` / `Exec` returns the parsed JSON response on HTTP `200`. Any other status
raises a `HelixError` whose `kind` is one of `Network`, `Remote`, `Serialization`,
or `InvalidUrl`. In Go, remote errors are returned as `*helix.HelixError` with
`StatusCode` populated; HTTP `409 Conflict` also wraps `helix.ErrConflict` and can
be checked with `helix.IsConflict(err)`. The SDKs do not retry conflicts
automatically, so retry only in application code when the operation is safe to
replay.

## Transactions

Every query — read or write — executes as a single transaction
with serializable snapshot isolation.

* **Serializable.** Transactions behave as if they executed one at a time, even
  when running concurrently.
* **Snapshot isolation.** Each transaction reads from a consistent point-in-time
  snapshot. Reads within a transaction are never affected by concurrent writes.
* **Automatic.** Transactions are implicit. Every query invocation is a
  transaction. There is no manual `BEGIN` / `COMMIT` / `ROLLBACK`.

Read-only queries never block writes. Write transactions are serialized through
the single writer process for correctness without distributed locking. See
[Guarantees](/database/guarantees) for the full consistency and durability
contract.

## Next Steps

<CardGroup cols={2}>
  <Card title="Querying Guide" icon="book-open" href="/database/querying-guide/overview">
    Tutorial walkthrough of the DSL with TypeScript, Rust, Go, Python, and JSON examples.
  </Card>

  <Card title="Parameters & bundles" icon="gear" href="/database/querying-guide/parameters-bundles">
    `defineParams`, dynamic requests, bundles, and the typed `call` helpers in depth.
  </Card>

  <Card title="Working with HelixDB" icon="rocket" href="/database/working-with-enterprise">
    Deploy-time and runtime workflow, query warming, and HTTP semantics.
  </Card>

  <Card title="Data Model" icon="diagram-project" href="/database/data-model">
    Nodes, edges, properties, and the labeled multigraph model.
  </Card>
</CardGroup>
