> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.ampdb.io/api/mcp` to find what you need.

# Lineage

Status: Unstable.

A [derived dataset](/datasets/derived-datasets) reads from other datasets, its dependencies, which can be derived too.
A dataset's **lineage** is that graph around it: **upstream**, the datasets it reads from, down to the raw datasets that
extract from a chain, and **downstream**, the datasets that read from it. Use upstream lineage to find where a dataset's
data comes from, and downstream lineage to find what a change to a dataset would affect before you make it.

The Admin API returns the graph in one request. `ampctl` has no command for it.

## Prerequisites

* Amp running, with its Admin API reachable, as in [Managing Datasets](/managing-amp/datasets#prerequisites).
* For the examples: the raw dataset `acme/eth_mainnet@1.0.0`, and a derived dataset `acme/token_analytics@1.0.0` whose
  manifest depends on `acme/eth_mainnet@1.0.0`, under the alias `eth`.

## Get a dataset's upstream lineage

:::terminal
```bash
curl 'http://localhost:1610/datasets/acme/token_analytics/versions/1.0.0/lineage'
```

```json
{
  "anchor": "acme/token_analytics@1.0.0",
  "nodes": [
    {
      "dataset": "acme/token_analytics@1.0.0",
      "kind": "manifest",
      "status": "ok",
      "resolved_hash": "d22760ee354621db13e962cd4e26f71dcb57e1b36f24bd93a8452c88fdbf38e1",
      "depth": 0
    },
    {
      "dataset": "acme/eth_mainnet@1.0.0",
      "kind": "evm-rpc",
      "status": "ok",
      "resolved_hash": "b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b",
      "depth": 1
    }
  ],
  "edges": [
    {
      "source": "acme/eth_mainnet@1.0.0",
      "target": "acme/token_analytics@1.0.0",
      "alias": "eth",
      "resolved_source": "acme/eth_mainnet@b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b"
    }
  ],
  "depth": 1,
  "truncated": false,
  "cycles": []
}
```
:::

The dataset you ask about is the **anchor**. Upstream lineage is the default direction.

The anchor can be any revision: a version, a manifest hash, `latest`, or `dev`, like
`/datasets/acme/token_analytics/versions/latest/lineage`. A manifest's dependencies can't: each names a version or a
manifest hash, and registering a manifest that depends on `@latest` or `@dev` fails with `INVALID_MANIFEST`.

## Get a dataset's downstream lineage

Ask from the raw dataset, with `direction=downstream`, to find what reads from it:

:::terminal
```bash
curl 'http://localhost:1610/datasets/acme/eth_mainnet/versions/1.0.0/lineage?direction=downstream'
```

```json
{
  "anchor": "acme/eth_mainnet@1.0.0",
  "nodes": [
    {
      "dataset": "acme/eth_mainnet@1.0.0",
      "kind": "evm-rpc",
      "status": "ok",
      "resolved_hash": "b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b",
      "depth": 0
    },
    {
      "dataset": "acme/token_analytics@1.0.0",
      "kind": "manifest",
      "status": "ok",
      "resolved_hash": "d22760ee354621db13e962cd4e26f71dcb57e1b36f24bd93a8452c88fdbf38e1",
      "depth": 1
    }
  ],
  "edges": [
    {
      "source": "acme/eth_mainnet@1.0.0",
      "target": "acme/token_analytics@1.0.0",
      "alias": "eth",
      "resolved_source": "acme/eth_mainnet@b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b"
    }
  ],
  "depth": 1,
  "truncated": false,
  "cycles": []
}
```
:::

Amp matches dependencies by the manifest they point to, not by how they're written: a dataset that depends on another
version of the same manifest, or on its hash, reads from the anchor too. Downstream datasets are named by the versions
their manifest is tagged with: a manifest tagged with two versions appears as two nodes.

`direction=both` returns both halves in one graph:

```bash
curl 'http://localhost:1610/datasets/acme/token_analytics/versions/1.0.0/lineage?direction=both&max_depth=2'
```

## Query parameters

| Parameter   | Type                                | Default    | Description                                                                                                                       |
| ----------- | ----------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `direction` | `upstream`, `downstream`, or `both` | `upstream` | Which way to walk from the anchor, like `direction=downstream`.                                                                   |
| `max_depth` | integer, at least 0                 | unlimited  | How many steps away from the anchor to go, like `max_depth=2`. With `both`, it applies to each direction.                         |
| `max_nodes` | integer, at least 0                 | unlimited  | The most datasets to return, like `max_nodes=50`. With `both`, it applies to each direction, so the graph can have twice as many. |

The anchor is always included, even with `max_nodes=0`.

## Reading the graph

**Edges point the way data flows**, from `source`, the dataset read from, to `target`, the dataset reading it, whichever
direction you walk. Read the graph as a data-flow diagram.

| Field       | Description                                                                                                                                                                                                                       |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `anchor`    | The dataset you asked about.                                                                                                                                                                                                      |
| `nodes`     | Every dataset reached. Each has its reference as `dataset`, its `kind` (`manifest` for derived datasets), the manifest hash it resolves to as `resolved_hash`, its `depth` (steps from the anchor, which is `0`), and a `status`. |
| `edges`     | Every dependency between them, each with its `source`, `target`, and `alias`.                                                                                                                                                     |
| `depth`     | The most steps from the anchor in the graph.                                                                                                                                                                                      |
| `truncated` | `true` when `max_depth` or `max_nodes` cut the graph short: some datasets past the limit aren't in it.                                                                                                                            |
| `cycles`    | The datasets that depend on each other in a cycle, if any. Empty normally.                                                                                                                                                        |

* **`source` is written the way the reading dataset's manifest wrote it**: a version, like `acme/eth_mainnet@1.0.0`,
  or a manifest hash. `resolved_source` is the manifest hash it points to now. A version points to the manifest last
  registered with it, so registering `1.0.0` again with another manifest moves every dependency on it.
* **`alias`** is the name the reading dataset's SQL uses for the dependency, like `eth` in `FROM eth.blocks`.
* **A node's `status`** is `ok`, or `missing` when its reference doesn't resolve to a registered dataset, like a
  dependency that was removed. A missing node has no `kind` or `resolved_hash`.

## Limits

* **Results can change between requests.** Revisions resolve when you ask: `dev` moves with each registration, `latest`
  when you register a higher version, and a version when it's registered again with another manifest. Downstream lineage
  also grows as datasets that read the anchor are registered. Ask about a manifest hash to keep the anchor itself from
  moving.
* **Downstream lineage reads every derived manifest** on each request, so it gets slower as you register more derived
  datasets. Set `max_depth` or `max_nodes` to bound it.

## Errors

| Status | Error code               | Cause                                                                                                                |
| ------ | ------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `400`  | `INVALID_PATH`           | The namespace, name, or revision isn't valid.                                                                        |
| `400`  | none                     | A query parameter has a value it doesn't take, like `direction=sideways`. The answer is plain text rather than JSON. |
| `404`  | `DATASET_NOT_FOUND`      | The anchor's dataset or revision isn't registered.                                                                   |
| `500`  | `RESOLVE_REVISION_ERROR` | Amp couldn't look up the anchor's revision.                                                                          |
| `500`  | `BUILD_LINEAGE_ERROR`    | Amp couldn't read a dataset or manifest while walking the graph.                                                     |

Query parameters other than those above are ignored.

See the [Admin API reference](/managing-amp/admin-api/datasets#get-a-datasets-lineage) for the full response schema.
