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

# Multi-Network Deployment

> Deploy and manage subgraphs across multiple blockchain networks

Graph Node supports indexing data from multiple blockchain networks simultaneously. This guide covers configuration and best practices for multi-network deployments.

## Overview

Multi-network support allows you to:

* Index the same contract deployed across different networks
* Aggregate data from multiple chains in a single subgraph
* Run one Graph Node instance serving multiple networks
* Scale across networks with different sharding strategies

## Configuration

### Basic Multi-Network Setup

Configure multiple chains in your Graph Node configuration file:

<CodeGroup>
  ```toml config.toml theme={null}
  [store]
  [store.primary]
  connection = "postgresql://graph:password@localhost:5432/graph-node"
  pool_size = 10

  [chains]
  ingestor = "block_ingestor_node"

  [chains.mainnet]
  shard = "primary"
  protocol = "ethereum"
  provider = [
    { label = "mainnet-1", url = "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY", features = ["archive", "traces"] },
    { label = "mainnet-2", url = "https://mainnet.infura.io/v3/YOUR_KEY", features = ["archive"] }
  ]

  [chains.polygon]
  shard = "primary"
  protocol = "ethereum"
  provider = [
    { label = "polygon-1", url = "https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEY", features = ["archive", "traces"] }
  ]

  [chains.arbitrum]
  shard = "primary"
  protocol = "ethereum"
  provider = [
    { label = "arbitrum-1", url = "https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY", features = ["archive", "traces"] }
  ]

  [chains.optimism]
  shard = "primary"
  protocol = "ethereum"
  provider = [
    { label = "optimism-1", url = "https://opt-mainnet.g.alchemy.com/v2/YOUR_KEY", features = ["archive"] }
  ]

  [deployment]
  [[deployment.rule]]
  # Deploy to primary shard and index nodes
  indexers = ["index_node_1", "index_node_2"]
  ```
</CodeGroup>

### Chain Configuration Options

<ParamField path="shard" type="String" required>
  Specifies which database shard stores this chain's data. Must reference a shard defined in `[store]`.
</ParamField>

<ParamField path="protocol" type="String" default="ethereum">
  The protocol type being indexed. Options: `ethereum`, `near`, `cosmos`, `arweave`, `starknet`.
</ParamField>

<ParamField path="polling_interval" type="Number" default="500">
  The polling interval for the block ingestor in milliseconds.
</ParamField>

<ParamField path="amp" type="String">
  The network name used by AMP for this chain. Set this when AMP uses a different name than graph-node.

  Example: `amp = "ethereum-mainnet"` on a chain named `mainnet`.
</ParamField>

<ParamField path="provider" type="Provider[]" required>
  A list of providers for that chain. See [Provider Configuration](#provider-configuration).
</ParamField>

### Provider Configuration

<ParamField path="label" type="String" required>
  The name of the provider, which will appear in logs.
</ParamField>

<ParamField path="url" type="String" required>
  The URL for the provider (RPC, WebSocket, or IPC endpoint).
</ParamField>

<ParamField path="features" type="String[]" default="[]">
  Array of features that the provider supports:

  * `archive`: Provider is an archive node with full historical state
  * `traces`: Provider supports `debug_traceBlockByNumber` for call tracing
  * `no_eip1898`: Provider doesn't support EIP-1898
  * `no_eip2718`: Provider doesn't return the `type` field in transaction receipts
  * `compression/gzip`, `compression/brotli`, `compression/deflate`: Provider supports request compression
</ParamField>

<ParamField path="headers" type="Object">
  HTTP headers to be added on every request.

  Example: `headers = { Authorization = "Bearer token" }`
</ParamField>

<ParamField path="limit" type="Number">
  The maximum number of subgraphs that can use this provider. Defaults to unlimited.
</ParamField>

<ParamField path="transport" type="String" default="rpc">
  Transport type. Options: `rpc`, `ws`, `ipc`.
</ParamField>

## Subgraph Manifest for Multiple Networks

### Single Network Deployment

<CodeGroup>
  ```yaml subgraph-mainnet.yaml theme={null}
  specVersion: 0.0.8
  schema:
    file: ./schema.graphql
  dataSources:
    - kind: ethereum/contract
      name: Token
      network: mainnet
      source:
        address: "0x1234567890123456789012345678901234567890"
        abi: ERC20
        startBlock: 12345678
      mapping:
        kind: ethereum/events
        apiVersion: 0.0.7
        language: wasm/assemblyscript
        entities:
          - Transfer
        abis:
          - name: ERC20
            file: ./abis/ERC20.json
        eventHandlers:
          - event: Transfer(indexed address,indexed address,uint256)
            handler: handleTransfer
        file: ./src/mapping.ts
  ```
</CodeGroup>

### Multi-Network Deployment

You can create separate manifests for each network:

<Tabs>
  <Tab title="Mainnet">
    ```yaml subgraph-mainnet.yaml theme={null}
    specVersion: 0.0.8
    schema:
      file: ./schema.graphql
    dataSources:
      - kind: ethereum/contract
        name: Token
        network: mainnet
        source:
          address: "0x1234567890123456789012345678901234567890"
          abi: ERC20
          startBlock: 12345678
        mapping:
          kind: ethereum/events
          apiVersion: 0.0.7
          language: wasm/assemblyscript
          entities:
            - Transfer
          abis:
            - name: ERC20
              file: ./abis/ERC20.json
          eventHandlers:
            - event: Transfer(indexed address,indexed address,uint256)
              handler: handleTransfer
          file: ./src/mapping.ts
    ```
  </Tab>

  <Tab title="Polygon">
    ```yaml subgraph-polygon.yaml theme={null}
    specVersion: 0.0.8
    schema:
      file: ./schema.graphql
    dataSources:
      - kind: ethereum/contract
        name: Token
        network: polygon
        source:
          address: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
          abi: ERC20
          startBlock: 23456789
        mapping:
          kind: ethereum/events
          apiVersion: 0.0.7
          language: wasm/assemblyscript
          entities:
            - Transfer
          abis:
            - name: ERC20
              file: ./abis/ERC20.json
          eventHandlers:
            - event: Transfer(indexed address,indexed address,uint256)
              handler: handleTransfer
          file: ./src/mapping.ts
    ```
  </Tab>

  <Tab title="Arbitrum">
    ```yaml subgraph-arbitrum.yaml theme={null}
    specVersion: 0.0.8
    schema:
      file: ./schema.graphql
    dataSources:
      - kind: ethereum/contract
        name: Token
        network: arbitrum-one
        source:
          address: "0xfedcbafedcbafedcbafedcbafedcbafedcbafed"
          abi: ERC20
          startBlock: 34567890
        mapping:
          kind: ethereum/events
          apiVersion: 0.0.7
          language: wasm/assemblyscript
          entities:
            - Transfer
          abis:
            - name: ERC20
              file: ./abis/ERC20.json
          eventHandlers:
            - event: Transfer(indexed address,indexed address,uint256)
              handler: handleTransfer
          file: ./src/mapping.ts
    ```
  </Tab>
</Tabs>

### Using Mustache Templates

Use templating to manage network-specific values:

<CodeGroup>
  ```yaml subgraph.template.yaml theme={null}
  specVersion: 0.0.8
  schema:
    file: ./schema.graphql
  dataSources:
    - kind: ethereum/contract
      name: Token
      network: {{network}}
      source:
        address: "{{address}}"
        abi: ERC20
        startBlock: {{startBlock}}
      mapping:
        kind: ethereum/events
        apiVersion: 0.0.7
        language: wasm/assemblyscript
        entities:
          - Transfer
        abis:
          - name: ERC20
            file: ./abis/ERC20.json
        eventHandlers:
          - event: Transfer(indexed address,indexed address,uint256)
            handler: handleTransfer
        file: ./src/mapping.ts
  ```

  ```json networks.json theme={null}
  {
    "mainnet": {
      "network": "mainnet",
      "address": "0x1234567890123456789012345678901234567890",
      "startBlock": 12345678
    },
    "polygon": {
      "network": "polygon",
      "address": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
      "startBlock": 23456789
    },
    "arbitrum": {
      "network": "arbitrum-one",
      "address": "0xfedcbafedcbafedcbafedcbafedcbafedcbafed",
      "startBlock": 34567890
    }
  }
  ```

  ```bash Deploy Script theme={null}
  #!/bin/bash

  # Generate and deploy for each network
  for network in mainnet polygon arbitrum; do
    echo "Deploying to $network..."
    
    # Generate network-specific manifest using mustache or similar
    mustache networks.json subgraph.template.yaml > subgraph.yaml
    
    # Build
    graph build
    
    # Deploy
    graph deploy \
      --node http://localhost:8020 \
      --ipfs http://localhost:5001 \
      myorg/my-subgraph-$network
  done
  ```
</CodeGroup>

## Database Sharding for Multiple Networks

For large-scale deployments, distribute networks across multiple database shards:

<CodeGroup>
  ```toml config.toml with Sharding theme={null}
  [store]
  # Primary shard for Ethereum mainnet
  [store.primary]
  connection = "postgresql://graph:password@mainnet-db:5432/graph-node"
  pool_size = 20

  # Shard for Layer 2 networks
  [store.layer2]
  connection = "postgresql://graph:password@layer2-db:5432/graph-node"
  pool_size = 15

  # Shard for other networks
  [store.other]
  connection = "postgresql://graph:password@other-db:5432/graph-node"
  pool_size = 10

  [chains]
  ingestor = "block_ingestor_node"

  # Ethereum mainnet on primary shard
  [chains.mainnet]
  shard = "primary"
  protocol = "ethereum"
  provider = [
    { label = "mainnet-1", url = "https://eth-mainnet.g.alchemy.com/v2/KEY", features = ["archive", "traces"] }
  ]

  # Layer 2 networks on layer2 shard
  [chains.polygon]
  shard = "layer2"
  protocol = "ethereum"
  provider = [
    { label = "polygon-1", url = "https://polygon-mainnet.g.alchemy.com/v2/KEY", features = ["archive"] }
  ]

  [chains.arbitrum]
  shard = "layer2"
  protocol = "ethereum"
  provider = [
    { label = "arbitrum-1", url = "https://arb-mainnet.g.alchemy.com/v2/KEY", features = ["archive"] }
  ]

  [chains.optimism]
  shard = "layer2"
  protocol = "ethereum"
  provider = [
    { label = "optimism-1", url = "https://opt-mainnet.g.alchemy.com/v2/KEY", features = ["archive"] }
  ]

  # Other networks on other shard
  [chains.bsc]
  shard = "other"
  protocol = "ethereum"
  provider = [
    { label = "bsc-1", url = "https://bsc-dataseed.binance.org", features = [] }
  ]

  [chains.avalanche]
  shard = "other"
  protocol = "ethereum"
  provider = [
    { label = "avalanche-1", url = "https://api.avax.network/ext/bc/C/rpc", features = [] }
  ]

  [deployment]
  # Network-specific deployment rules
  [[deployment.rule]]
  match = { network = "mainnet" }
  shard = "primary"
  indexers = ["index_node_mainnet_1", "index_node_mainnet_2"]

  [[deployment.rule]]
  match = { network = ["polygon", "arbitrum", "optimism"] }
  shard = "layer2"
  indexers = ["index_node_layer2_1", "index_node_layer2_2"]

  [[deployment.rule]]
  match = { network = ["bsc", "avalanche"] }
  shard = "other"
  indexers = ["index_node_other_1"]

  # Default rule
  [[deployment.rule]]
  indexers = ["index_node_default"]
  ```
</CodeGroup>

## Running Graph Node with Configuration

<CodeGroup>
  ```bash Start with Config File theme={null}
  # Using Docker
  docker run -it \
    -v $(pwd)/config.toml:/config.toml \
    -p 8000:8000 \
    -p 8020:8020 \
    graphprotocol/graph-node:latest \
    --config /config.toml

  # From source
  cargo run -p graph-node --release -- --config config.toml
  ```
</CodeGroup>

<Note>
  When using a configuration file, you cannot use the command-line options `--postgres-url`, `--postgres-secondary-hosts`, or `--postgres-host-weights`.
</Note>

## Provider Management

### Multiple Providers per Network

Configure redundant providers for reliability:

<CodeGroup>
  ```toml Multiple Providers theme={null}
  [chains.mainnet]
  shard = "primary"
  provider = [
    # Primary provider with all features
    { 
      label = "alchemy-mainnet",
      url = "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
      features = ["archive", "traces"],
      headers = { "X-Custom-Header" = "value" }
    },
    # Backup provider
    { 
      label = "infura-mainnet",
      url = "https://mainnet.infura.io/v3/YOUR_KEY",
      features = ["archive"]
    },
    # Local node
    { 
      label = "local-mainnet",
      url = "http://localhost:8545",
      features = ["archive", "traces"],
      limit = 5  # Limit to 5 subgraphs
    }
  ]
  ```
</CodeGroup>

### Provider Limits

Control how many subgraphs can use each provider:

<CodeGroup>
  ```toml Provider Limits theme={null}
  [chains.mainnet]
  shard = "primary"
  provider = [
    # Unlimited (default)
    { label = "primary", url = "https://primary.com/rpc", features = ["archive", "traces"] },
    
    # Limited by node name
    { 
      label = "secondary",
      url = "https://secondary.com/rpc",
      features = ["archive"],
      match = [
        { name = "index_node_1", limit = 10 },
        { name = "index_node_2", limit = 5 }
      ]
    }
  ]
  ```
</CodeGroup>

## Network-Specific Mappings

Handle network-specific logic in your mappings:

<CodeGroup>
  ```typescript Network-Specific Logic theme={null}
  import { dataSource } from '@graphprotocol/graph-ts'

  export function handleTransfer(event: Transfer): void {
    let network = dataSource.network()
    
    // Network-specific handling
    if (network == 'mainnet') {
      // Ethereum mainnet logic
      handleMainnetTransfer(event)
    } else if (network == 'polygon') {
      // Polygon-specific logic
      handlePolygonTransfer(event)
    } else if (network == 'arbitrum-one') {
      // Arbitrum-specific logic
      handleArbitrumTransfer(event)
    }
  }

  function handleMainnetTransfer(event: Transfer): void {
    // Higher gas costs, different transaction patterns
    let entity = new Transfer(event.transaction.hash.toHex())
    entity.gasPrice = event.transaction.gasPrice
    entity.save()
  }

  function handlePolygonTransfer(event: Transfer): void {
    // Lower gas costs, higher throughput
    let entity = new Transfer(event.transaction.hash.toHex())
    entity.network = 'polygon'
    entity.save()
  }
  ```
</CodeGroup>

## Monitoring Multiple Networks

Query indexing status across all networks:

<CodeGroup>
  ```graphql Query All Networks theme={null}
  query {
    indexingStatuses {
      subgraph
      synced
      health
      chains {
        network
        chainHeadBlock {
          number
        }
        latestBlock {
          number
        }
        earliestBlock {
          number
        }
      }
    }
  }
  ```

  ```bash Check Status theme={null}
  curl -X POST \
    -H "Content-Type: application/json" \
    -d '{"query": "{ indexingStatuses { subgraph chains { network latestBlock { number } chainHeadBlock { number } } } }" }' \
    http://localhost:8000/graphql
  ```
</CodeGroup>

## Best Practices

<Tabs>
  <Tab title="Configuration">
    1. **Separate shards by network load** - Put high-volume networks on dedicated shards
    2. **Use multiple providers** - Configure redundant RPC endpoints for each network
    3. **Set appropriate pool sizes** - Allocate connection pools based on expected load
    4. **Use deployment rules** - Route subgraphs to appropriate nodes and shards
    5. **Name chains consistently** - Use standard network names that match graph-cli
  </Tab>

  <Tab title="Performance">
    1. **Optimize startBlock per network** - Different networks have different relevant start blocks
    2. **Use archive nodes** - Required for historical queries on all networks
    3. **Enable tracing selectively** - Only enable on providers/networks that support it
    4. **Monitor polling intervals** - Adjust based on network block times
    5. **Scale resources per network** - Allocate more resources to high-throughput networks
  </Tab>

  <Tab title="Reliability">
    1. **Test each network separately** - Deploy and verify on one network before expanding
    2. **Handle network-specific quirks** - Account for differences in block times, reorg frequency
    3. **Set appropriate reorg thresholds** - Different networks have different finality times
    4. **Monitor provider health** - Track RPC endpoint availability and latency
    5. **Use provider limits wisely** - Prevent overloading shared infrastructure
  </Tab>

  <Tab title="Maintenance">
    1. **Version control configurations** - Track changes to network configurations
    2. **Document network-specific behavior** - Note any special handling per network
    3. **Plan for network upgrades** - Be aware of hard forks and protocol changes
    4. **Test provider failover** - Verify backup providers work correctly
    5. **Monitor costs** - Track RPC usage across all networks
  </Tab>
</Tabs>

## Environment Variables for Multi-Network

Key environment variables when running multiple networks:

<ParamField path="ETHEREUM_REORG_THRESHOLD" type="Number" default="250">
  Maximum expected reorg size. May need to be set differently per network.
</ParamField>

<ParamField path="ETHEREUM_POLLING_INTERVAL" type="Number" default="500">
  Polling interval in milliseconds. Consider network block times.
</ParamField>

<ParamField path="GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE" type="Number" default="1000">
  Maximum blocks to scan per request. Adjust based on network throughput.
</ParamField>

<ParamField path="GRAPH_ETHEREUM_TARGET_TRIGGERS_PER_BLOCK_RANGE" type="Number" default="100">
  Target triggers per batch. Optimize based on event density.
</ParamField>

## Troubleshooting

<Tabs>
  <Tab title="Network Not Found">
    **Problem:** Error says network is not configured

    **Solutions:**

    * Verify network name in subgraph.yaml matches config.toml
    * Check that the chain section exists: `[chains.network-name]`
    * Ensure Graph Node was restarted after config changes
    * Validate config file: `graph-node --config config.toml config check`
  </Tab>

  <Tab title="Provider Issues">
    **Problem:** RPC provider errors or failures

    **Solutions:**

    * Test provider URL directly with curl
    * Verify API keys are valid and not rate-limited
    * Check provider features match requirements (archive, traces)
    * Try different transport (rpc vs ws)
    * Review provider logs for specific errors
  </Tab>

  <Tab title="Sync Delays">
    **Problem:** One network syncing slower than others

    **Solutions:**

    * Check if provider is rate-limiting
    * Verify provider has archive capability
    * Reduce `GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE` for that network
    * Allocate more database connections via pool\_size
    * Consider moving to dedicated shard
  </Tab>

  <Tab title="Deployment Routing">
    **Problem:** Subgraph deployed to wrong shard or node

    **Solutions:**

    * Check deployment rules match subgraph name/network
    * Verify rule ordering (first match wins)
    * Test with: `graphman config place myorg/subgraph network`
    * Ensure indexer nodes are running with correct node IDs
    * Review `[deployment]` section in config file
  </Tab>
</Tabs>

## Next Steps

* Review the [subgraph manifest specification](/deployment/subgraph-manifest)
* Learn about [deploying subgraphs](/deployment/deploying-subgraphs)
* Explore [advanced configuration](/configuration/advanced-config)
* Set up [database sharding](/operations/sharding)
