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

# Configuration File

> Advanced TOML configuration for Graph Node

A TOML configuration file enables more complex Graph Node configurations than those exposed through CLI options. The configuration file location is specified with the `--config` command line flag.

<Warning>
  When using a configuration file, you cannot use the `--postgres-url`, `--postgres-secondary-hosts`, and `--postgres-host-weights` CLI options.
</Warning>

## Configuration Structure

The TOML configuration file consists of four main sections:

<CardGroup cols={2}>
  <Card title="[chains]" icon="link">
    Sets endpoints to blockchain clients
  </Card>

  <Card title="[store]" icon="database">
    Describes available databases and shards
  </Card>

  <Card title="[ingestor]" icon="download">
    Sets the node responsible for block ingestion
  </Card>

  <Card title="[deployment]" icon="rocket">
    Describes how to place newly deployed subgraphs
  </Card>
</CardGroup>

<Note>
  Many configuration sections support environment variable expansion, especially Postgres connection strings. The official `graph-node` Docker image includes [`envsubst`](https://github.com/a8m/envsubst) for complex use cases.
</Note>

## Basic Configuration

The simplest configuration is equivalent to using the `--postgres-url` command line option:

```toml theme={null}
[store]
[store.primary]
connection = "postgresql://graph:password@localhost/graph"

[deployment]
[[deployment.rule]]
indexers = [ "index_node_1", "index_node_2" ]
```

## Store Configuration

The `[store]` section defines database connections and sharding setup. At minimum, you must configure a primary shard.

### Single Database Setup

```toml theme={null}
[store]
[store.primary]
connection = "postgresql://graph:${PGPASSWORD}@primary/graph"
pool_size = 10
```

### Connection String Format

The `connection` string must be a valid [libpq connection string](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING). Environment variables embedded in the string are expanded before passing to Postgres.

```toml theme={null}
connection = "postgresql://graph:${PGPASSWORD}@${DB_HOST}/graph"
```

### Connection Pool Size

Each shard must specify how many database connections each `graph-node` instance maintains in its connection pool.

<Accordion title="Fixed Pool Size">
  Set a single value for all nodes:

  ```toml theme={null}
  [store.primary]
  connection = "postgresql://graph:password@primary/graph"
  pool_size = 10
  ```
</Accordion>

<Accordion title="Rule-Based Pool Size">
  Use different pool sizes for different node types based on `node_id` patterns:

  ```toml theme={null}
  [store.primary]
  connection = "postgresql://graph:password@primary/graph"
  pool_size = [
    { node = "index_node_general_.*", size = 20 },
    { node = "index_node_special_.*", size = 30 },
    { node = "query_node_.*", size = 80 }
  ]
  ```

  Rules are checked in order, and the first matching rule is used. If no rule matches, configuration loading fails.
</Accordion>

<Warning>
  Always run `graphman config pools $all_nodes` after changing pool configuration to verify the expected connection counts. Replace `$all_nodes` with a space-separated list of all node names using this configuration.
</Warning>

## Chain Configuration

The `[chains]` section controls blockchain provider connections and metadata storage.

### Chain Structure

Configure a chain named `mainnet` in the `[chains.mainnet]` section:

```toml theme={null}
[chains]
ingestor = "block_ingestor_node"

[chains.mainnet]
shard = "vip"
protocol = "ethereum"
polling_interval = 500
amp = "ethereum-mainnet"
provider = [
  { label = "mainnet1", url = "http://ethereum-node-1:8545", features = [] },
  { label = "mainnet2", url = "http://ethereum-node-2:8545", features = ["archive", "traces"] }
]
```

### Chain Parameters

* **`shard`**: Database shard where chain data is stored
* **`protocol`**: Protocol type (`ethereum`, `near`, `cosmos`, `arweave`, `starknet`). Default: `ethereum`
* **`polling_interval`**: Block ingestor polling interval in milliseconds. Default: `500`
* **`amp`**: Network name used by AMP for this chain. Defaults to chain name. Set when AMP uses different naming (e.g., `amp = "ethereum-mainnet"` for chain named `mainnet`)
* **`provider`**: List of providers for this chain

### Provider Configuration

Each provider has:

* **`label`**: Provider name appearing in logs
* **`details`**: Provider connection details

<CodeGroup>
  ```toml Web3 Provider theme={null}
  [chains.mainnet]
  shard = "primary"
  provider = [
    {
      label = "mainnet",
      url = "http://ethereum-node:8545",
      features = ["archive", "traces"],
      headers = { Authorization = "Bearer token123" }
    }
  ]
  ```

  ```toml Firehose Provider theme={null}
  [chains.near-mainnet]
  shard = "blocks_b"
  protocol = "near"
  provider = [
    {
      label = "near-firehose",
      details = {
        type = "firehose",
        url = "https://firehose.example.com",
        key = "api-key-here",
        features = ["compression", "filters"]
      }
    }
  ]
  ```

  ```toml Multiple Networks theme={null}
  [chains]
  ingestor = "block_ingestor_node"

  [chains.mainnet]
  shard = "vip"
  amp = "ethereum-mainnet"
  provider = [
    { label = "mainnet1", url = "http://eth-node-1:8545", features = [] },
    { label = "mainnet2", url = "http://eth-node-2:8545", features = ["archive", "traces"] }
  ]

  [chains.sepolia]
  shard = "primary"
  provider = [
    { label = "sepolia", url = "http://sepolia-node:8545", features = [] }
  ]

  [chains.near-mainnet]
  shard = "blocks_b"
  protocol = "near"
  provider = [
    {
      label = "near",
      details = {
        type = "firehose",
        url = "https://near-firehose.example.com",
        key = "api-key",
        features = ["compression", "filters"]
      }
    }
  ]
  ```
</CodeGroup>

### Provider Details

* **`type`**: `web3` (default), `firehose`, or `web3call`
* **`transport`**: `rpc` (default), `ws`, or `ipc`
* **`url`**: Provider endpoint URL
* **`features`**: Array of supported features:
  * `traces`: Supports `debug_traceBlockByNumber` for call tracing
  * `archive`: Archive node with full historical state
  * `no_eip1898`: Doesn't support EIP-1898 (block parameter by hash/number object)
  * `no_eip2718`: Doesn't return `type` field in receipts (pre-EIP-2718 chains)
  * `compression/<method>`: Supports compression (`gzip`, `brotli`, or `deflate`)
  * For Firehose: `compression` and `filters`
* **`headers`**: HTTP headers for every request. Default: none
* **`limit`**: Maximum subgraphs using this provider. Default: unlimited
* **`token`**: Bearer token for Firehose providers
* **`key`**: API key for Firehose providers

### Provider Limits (Experimental)

<Warning>
  This feature is experimental and may be removed in future releases.
</Warning>

Limit the number of subgraphs per provider using node name patterns:

```toml theme={null}
[chains.mainnet]
shard = "vip"
provider = [
  { label = "mainnet-0", url = "http://node-0:8545", features = [] },
  {
    label = "mainnet-1",
    url = "http://node-1:8545",
    features = [],
    match = [
      { name = "some_node_.*", limit = 10 },
      { name = "other_node_.*", limit = 0 }
    ]
  }
]
```

Nodes named `some_node_.*` use `mainnet-1` for at most 10 subgraphs, then fall back to `mainnet-0`. Nodes named `other_node_.*` never use `mainnet-1`.

<Note>
  At least one provider should be unlimited. If a node's name doesn't match any rule, that provider is disabled for that node.
</Note>

## Deployment Configuration

The `[deployment]` section controls where new subgraph deployments are placed, determining both the storage shard and indexing node.

### Deployment Rules

Rules are evaluated in order. The first matching rule determines placement.

```toml theme={null}
[deployment]

# VIP subgraphs
[[deployment.rule]]
match = { name = "(vip|important)/.*" }
shard = "vip"
indexers = [ "index_node_vip_0", "index_node_vip_1" ]

# Kovan network subgraphs
[[deployment.rule]]
match = { network = "kovan" }
# No shard specified = uses 'primary'
indexers = [ "index_node_kovan_0" ]

# Multiple networks
[[deployment.rule]]
match = { network = [ "xdai", "poa-core" ] }
indexers = [ "index_node_other_0" ]

# Default catch-all rule (no match = matches everything)
[[deployment.rule]]
shards = [ "sharda", "shardb" ]
indexers = [
  "index_node_community_0",
  "index_node_community_1",
  "index_node_community_2",
  "index_node_community_3",
  "index_node_community_4",
  "index_node_community_5"
]
```

### Rule Matching

The `match` element can contain:

* **`name`**: [Regular expression](https://docs.rs/regex/1.4.2/regex/#syntax) matched against subgraph name
* **`network`**: String or list of strings compared to deployment's network

<Warning>
  The last rule must not have a `match` statement to ensure all deployments have a valid placement.
</Warning>

### Rule Actions

* **`shard`**: Storage shard name (default: `primary`)
* **`shards`**: List of shards (system chooses the one with fewest active deployments)
* **`indexers`**: List of indexing nodes (deployment spreads evenly across listed nodes)

<Note>
  Indexer names must match the `--node-id` values used when starting index nodes.
</Note>

## Query Nodes

Configure nodes as query-only (no indexing) by adding to `[general]`:

```toml theme={null}
[general]
query = "query_node_.*"
```

Nodes with `--node-id` matching the regex will:

* Only respond to queries
* Not connect to configured blockchain providers
* Not perform any indexing

## Configuration Validation

Validate configuration file syntax and consistency:

```bash theme={null}
graph-node --config config.toml config check
```

This checks for:

* Syntax errors
* Internal inconsistencies
* Undeclared shards referenced in deployment rules
* Invalid configuration combinations

## Simulating Deployment Placement

Test where a subgraph would be deployed without making changes:

```bash theme={null}
graphman --config config.toml config place some/subgraph mainnet
```

Output shows:

* Database shard for subgraph data
* List of potential indexing nodes
* Selection logic (node with fewest current subgraphs)

## Complete Example

<Accordion title="Full Production Configuration">
  ```toml theme={null}
  # General settings
  [general]
  query = "query_node_.*"

  # Store configuration
  [store]
  [store.primary]
  connection = "postgresql://graph:${PGPASSWORD}@primary-db/graph"
  weight = 0
  pool_size = [
    { node = "index_node_.*", size = 20 },
    { node = "query_node_.*", size = 80 }
  ]

  [store.primary.replicas.repl1]
  connection = "postgresql://graph:${PGPASSWORD}@primary-repl1/graph"
  weight = 1

  [store.primary.replicas.repl2]
  connection = "postgresql://graph:${PGPASSWORD}@primary-repl2/graph"
  weight = 1

  [store.vip]
  connection = "postgresql://graph:${PGPASSWORD}@vip-db/graph"
  weight = 1
  pool_size = 25

  [store.vip.replicas.repl1]
  connection = "postgresql://graph:${PGPASSWORD}@vip-repl1/graph"
  weight = 1

  # Chain configuration
  [chains]
  ingestor = "block_ingestor_node"

  [chains.mainnet]
  shard = "vip"
  amp = "ethereum-mainnet"
  polling_interval = 500
  provider = [
    {
      label = "mainnet-archive",
      url = "http://eth-archive:8545",
      features = ["archive", "traces"],
      headers = { Authorization = "Bearer ${ETH_API_TOKEN}" }
    },
    {
      label = "mainnet-regular",
      url = "http://eth-regular:8545",
      features = []
    }
  ]

  [chains.sepolia]
  shard = "primary"
  provider = [
    { label = "sepolia", url = "http://sepolia:8545", features = [] }
  ]

  # Deployment rules
  [deployment]

  [[deployment.rule]]
  match = { name = "(vip|production)/.*" }
  shard = "vip"
  indexers = [ "index_node_vip_0", "index_node_vip_1" ]

  [[deployment.rule]]
  match = { network = "sepolia" }
  indexers = [ "index_node_test_0" ]

  [[deployment.rule]]
  # Default catch-all
  shards = [ "primary" ]
  indexers = [
    "index_node_community_0",
    "index_node_community_1",
    "index_node_community_2"
  ]
  ```
</Accordion>
