> ## 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.

# Overview

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

This guide is a tutorial walkthrough of the HelixDB query language. Each page builds
on the last, starting from the simplest possible read and ending at parameter-bound
bundles. Key examples show the **TypeScript**, **Rust**, **Go**, **Python**, and **JSON** forms
across the guide, so you can pick a client and follow along or skim across the surfaces
to see how they relate.

These forms are not different query languages; they are encodings of
the same query AST. The TypeScript, Rust, Go, and Python DSLs are builders that emit the JSON
shape directly. If you copy the JSON column into a `POST /v1/query` body, it will
execute the same query as the DSL above it.

## Installing the SDKs

To follow along in TypeScript, Rust, Go, or Python, install the SDK for that language. All
four emit the same query AST, so you can switch between them — or use the JSON
column directly and skip the SDK entirely.

<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).

## The running example

Every page in this guide uses one small social-graph schema, so each new step plugs
into a domain you already know.

* **Nodes:** `User` (`username`, `tier`, `createdAt`), `Post` (`title`, `body`,
  `embedding`, `createdAt`), `Tag` (`name`).
* **Edges:** `FOLLOWS` (User → User), `AUTHORED` (User → Post), `LIKED` (User → Post),
  `TAGGED` (Post → Tag).
* **Indexes:** a unique-equality index on `User.username`, a vector index on
  `Post.embedding`, a text index on `Post.body`.

Index setup itself is covered on the [Search](/database/querying-guide/search) page;
for now assume they exist.

## How a query is shaped

Every query — read or write — is a small pipeline:

1. Open a batch with `readBatch()` or `writeBatch()`.
2. Bind one or more named sub-results with `.varAs("name", traversal)`. A traversal
   always starts from `g()` and chains steps until it produces nodes, edges, or a
   terminal value.
3. Choose which bound names to surface to the caller with `.returning([...])`.

The TypeScript shell:

```ts theme={"languages":{"custom":["languages/helixql.json"]}}
readBatch()
  .varAs("name", g().someSource().someStep())
  .varAs("other", g().someSource().someStep())
  .returning(["name", "other"]);
```

The Rust shell is identical except for naming conventions (`read_batch`, `var_as`,
`returning`). Go uses `helix.ReadQuery("name")`, `VarAs`, and variadic `Returning`.
The JSON shell is what the batch serializes to: a top-level
`{queries: [...], returns: [...]}` object, with each `varAs` producing one
`{Query: {name, steps, condition}}` entry. The
[Reading nodes](/database/querying-guide/reading-nodes) page covers the shell step by
step; this overview just shows the finished product.

## A full first example

Fetch a user by `username` and the ten most recent posts they authored. This example
takes no parameters; it hard-codes `"alice"` and a limit of `10` so the JSON column is
unambiguous. Parameter binding is introduced on the
[Filtering](/database/querying-guide/filtering) and
[Parameters & bundles](/database/querying-guide/parameters-bundles) pages.

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

  const aliceFeed = readBatch()
    .varAs("user", g().nWhere(SourcePredicate.eq("username", "alice")))
    .varAs(
      "posts",
      g()
        .n(NodeRef.var("user"))
        .out("AUTHORED")
        .orderBy("createdAt", Order.Desc)
        .limit(10)
        .project([
          PropertyProjection.renamed("$id", "post_id"),
          PropertyProjection.new("title"),
          PropertyProjection.new("createdAt"),
        ]),
    )
    .returning(["user", "posts"]);

  const request = aliceFeed.toDynamicRequest(); // POST this to /v1/query
  ```

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

  #[register]
  pub fn alice_feed() -> ReadBatch {
      read_batch()
          .var_as(
              "user",
              g().n_where(SourcePredicate::eq("username", "alice")),
          )
          .var_as(
              "posts",
              g().n(NodeRef::var("user"))
                  .out(Some("AUTHORED"))
                  .order_by("createdAt", Order::Desc)
                  .limit(10usize)
                  .project(vec![
                      PropertyProjection::renamed("$id", "post_id"),
                      PropertyProjection::new("title"),
                      PropertyProjection::new("createdAt"),
                  ]),
          )
          .returning(["user", "posts"])
  }
  ```

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

  func AliceFeed() helix.Request {
  	return helix.ReadQuery("alice_feed").
  		VarAs("user", helix.G().NWhere(helix.SourceEq("username", "alice"))).
  		VarAs("posts",
  			helix.G().
  				N(helix.NodeVar("user")).
  				Out("AUTHORED").
  				OrderBy("createdAt", helix.OrderDesc).
  				Limit(10).
  				Project(
  					helix.ProjectPropAs("$id", "post_id"),
  					helix.ProjectProp("title"),
  					helix.ProjectProp("createdAt"),
  				),
  		).
  		Returning("user", "posts")
  }
  ```

  ```json JSON theme={"languages":{"custom":["languages/helixql.json"]}}
  {
    "request_type": "read",
    "query": {
      "queries": [
        {
          "Query": {
            "name": "user",
            "steps": [
              { "NWhere": { "Eq": ["username", { "String": "alice" }] } }
            ],
            "condition": null
          }
        },
        {
          "Query": {
            "name": "posts",
            "steps": [
              { "N": { "Var": "user" } },
              { "Out": "AUTHORED" },
              { "OrderBy": ["createdAt", "Desc"] },
              { "Limit": 10 },
              {
                "Project": [
                  { "source": "$id",       "alias": "post_id"   },
                  { "source": "title",     "alias": "title"     },
                  { "source": "createdAt", "alias": "createdAt" }
                ]
              }
            ],
            "condition": null
          }
        }
      ],
      "returns": ["user", "posts"]
    }
  }
  ```
</CodeGroup>

Two things to notice:

* The `posts` traversal starts from `NodeRef.var("user")` — that's how one named
  binding feeds into the next. The same name appears as `{"N": {"Var": "user"}}` in
  the JSON.
* The TypeScript, Rust, Go, and Python DSLs surface friendly `nWithLabel` / `n_with_label` /
  `NWithLabel` alias, but this example uses `nWhere(SourcePredicate.eq("username", "alice"))`
  directly because the read is anchored on a unique property, not a label scan. The
  next page covers when to use each anchor.

## Sending the request

The JSON above is the actual body for `POST /v1/query`. Below are the same request
in multiple transports — TypeScript, Rust, Go, and Python using their SDK clients, and `curl`
straight from the shell. The transports are interchangeable; pick whichever fits your
environment.

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

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

  const { user, posts } = await client
    .query<{ user: unknown; posts: unknown }>()
    .dynamic(request) // from .toDynamicRequest() above
    .send();
  ```

  ```rust Rust theme={"languages":{"custom":["languages/helixql.json"]}}
  // alice_feed() returns the request to POST to /v1/query.
  use helix_db::Client;

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

  let response: serde_json::Value = client
      .query()
      .dynamic(alice_feed())
      .send()
      .await?;

  let user = &response["user"];
  let posts = &response["posts"];
  ```

  ```go Go theme={"languages":{"custom":["languages/helixql.json"]}}
  // AliceFeed() returns the request to POST to /v1/query.
  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 {
  	User  []map[string]any `json:"user"`
  	Posts []map[string]any `json:"posts"`
  }
  if err := client.Exec(ctx, AliceFeed(), &response); err != nil {
  	return err
  }

  user := response.User
  posts := response.Posts
  ```

  ```bash curl theme={"languages":{"custom":["languages/helixql.json"]}}
  # Save the JSON envelope to a file (or inline it with --data-raw '...').
  cat > /tmp/alice-feed.json <<'EOF'
  {
    "request_type": "read",
    "query": {
      "queries": [
        { "Query": { "name": "user", "steps": [
          { "NWhere": { "Eq": ["username", { "String": "alice" }] } }
        ], "condition": null } },
        { "Query": { "name": "posts", "steps": [
          { "N": { "Var": "user" } },
          { "Out": "AUTHORED" },
          { "OrderBy": ["createdAt", "Desc"] },
          { "Limit": 10 },
          { "Project": [
            { "source": "$id",       "alias": "post_id"   },
            { "source": "title",     "alias": "title"     },
            { "source": "createdAt", "alias": "createdAt" }
          ] }
        ], "condition": null } }
      ],
      "returns": ["user", "posts"]
    }
  }
  EOF

  curl -sS -X POST https://helix.example.com/v1/query \
    -H "content-type: application/json" \
    --data-binary @/tmp/alice-feed.json
  ```
</CodeGroup>

The response is a JSON object keyed by the names from `.returning([...])` — here
`{ "user": [...], "posts": [...] }`. Each value is the list of rows produced by that
named binding.

The [Parameters and bundles](/database/querying-guide/parameters-bundles) page shows
how to bind parameters and organize queries into a `queries.json` bundle.

## How to read this guide

Each page leads with a short intro, then `<CodeGroup>` blocks in all four forms.
TypeScript is the lead tab; Rust mirrors it with snake\_case names and trailing
underscores for keywords (`where_`, `in_`, `as_`); Go mirrors the same AST via
`helix.ReadQuery` / `helix.WriteQuery`; and JSON is the serialized AST you POST to
`/v1/query`. Pages can be read in any order.

## Next Steps

<CardGroup cols={2}>
  <Card title="Reading nodes and edges" icon="circle-nodes" href="/database/querying-guide/reading-nodes">
    Source anchors: `n` by id, `nWithLabel`, `nWhere`, and the edge equivalents.
  </Card>

  <Card title="Traversals" icon="diagram-project" href="/database/querying-guide/traversals">
    Walking the graph: `out`, `in`, `both`, edge variants, multi-hop chains.
  </Card>

  <Card title="Filtering, ordering, paging" icon="filter" href="/database/querying-guide/filtering">
    Predicates, ordering, and slicing the result stream.
  </Card>

  <Card title="Projections" icon="table-columns" href="/database/querying-guide/projections">
    Shaping the output: `values`, `valueMap`, `project`, `projectBindings`, aggregations.
  </Card>

  <Card title="Mutations" icon="pen-to-square" href="/database/querying-guide/mutations">
    `writeBatch`, `addN`, `addE`, `setProperty`, `drop`.
  </Card>

  <Card title="Vector and text search" icon="magnifying-glass" href="/database/querying-guide/search">
    `vectorSearchNodes`, `textSearchNodes`, follow-on traversal from hits.
  </Card>

  <Card title="Advanced patterns" icon="code-branch" href="/database/querying-guide/advanced">
    `repeat`, `union`, `choose`, `coalesce`, `optional`, `varAsIf`, `forEachParam`, `bind`.
  </Card>

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