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

# Multichain Indexing

> Combine data from multiple chains in a single Squid SDK indexer.

Squids can extract data from multiple blockchains into a shared data sink. When data is [stored to PostgreSQL](../writing-to-postgres), it can be served as a unified multichain [GraphQL API](../serving-graphql).

<Tip>
  Multichain indexing enables powerful cross-chain analytics and unified data
  access across different blockchain networks.
</Tip>

## Setup

To index multiple chains, run one [processor](../../design) per source network:

### 1. Create separate entry points

Make a separate entry point (`main.ts` or equivalent) for each processor:

```bash theme={"system"}
├── src
│   ├── bsc
│   │   ├── main.ts
│   │   └── processor.ts
│   ├── eth
│   │   ├── main.ts
│   │   └── processor.ts
```

<Note>
  Alternatively, parameterize your processor using environment variables. You
  can [set these on a per-processor basis](/en/cloud/reference/manifest#processor)
  if you use a deployment manifest.
</Note>

### 2. Configure processor commands

Add `sqd` commands for running each processor to [`commands.json`](/en/cloud/reference/cli/commands-json):

```json commands.json theme={"system"}
{
  "process:eth": {
    "deps": ["build", "migration:apply"],
    "cmd": ["node", "lib/eth/main.js"]
  },
  "process:bsc": {
    "deps": ["build", "migration:apply"],
    "cmd": ["node", "lib/bsc/main.js"]
  }
}
```

<Info>
  See the [full
  example](https://github.com/subsquid-labs/multichain-transfers-example/blob/master/commands.json)
  in the multichain transfers repository.
</Info>

### 3. Configure deployment manifest

If you plan to use [`sqd run`](/en/cloud/reference/cli/run) for local runs or deploy to [SQD Cloud](/en/cloud/overview), list your processors in the `deploy.processor` section of your [deployment manifest](/en/cloud/reference/manifest#processor):

```yaml squid.yaml theme={"system"}
deploy:
  processor:
    - name: eth-processor
      cmd: ["sqd", "process:prod:eth"]
    - name: bsc-processor
      cmd: ["sqd", "process:prod:bsc"]
```

<Warning>
  Make sure to give each processor a unique name to avoid conflicts.
</Warning>

## PostgreSQL Configuration

When using PostgreSQL, ensure the following:

### 1. Unique state schema for each processor

Each processor needs its own state schema to track sync progress independently:

```typescript src/bsc/main.ts theme={"system"}
run(
  dataSource,
  new TypeormDatabase({
    stateSchema: "bsc_processor",
  }),
  async (ctx) => {
    // BSC processing logic
  }
);
```

```typescript src/eth/main.ts theme={"system"}
run(
  dataSource,
  new TypeormDatabase({
    stateSchema: "eth_processor",
  }),
  async (ctx) => {
    // Ethereum processing logic
  }
);
```

<Note>
  State schemas track the sync progress of each processor independently,
  enabling reliable multichain indexing.
</Note>

### 2. Shared schema and API

The [schema](../../reference/schema-files/schema-files-codegen) and [GraphQL API](../serving-graphql) should be shared among all processors to provide a unified data model.

This setup keeps every chain in **one shared schema**: the entity tables are common to all processors, so a single GraphQL API serves the combined data. As discussed below, this can sometimes lead to write concurrency.

<Note>
  For full isolation instead, give each processor its own [`DB_SCHEMA`](../../reference/data-stores/typeorm-store#db_schema) — one Postgres schema per chain. The processors' tables never overlap, which removes cross-chain write concurrency entirely, and each chain can also keep its state in the same schema (set `stateSchema` to the same value). The cost is on the serving side: an OpenReader instance reads a single `DB_SCHEMA`, so you expose one GraphQL API per chain (or add a stitching/gateway layer) rather than the unified API above. Choose shared schemas for a unified API, isolated schemas to avoid separating the data per-chain manually.
</Note>

### Handling concurrency

* Cross-chain data dependencies are to be avoided. With the [default isolation level](../../reference/data-stores/typeorm-store#typeormdatabase-constructor-arguments) used by `TypeormDatabase`, `SERIALIZABLE`, one of the processors will crash with an error whenever two cross-dependent transactions are submitted to the database simultaneously. It will write the correct data when restarted, but such restarts can impact performance, especially in squids that use many (>5) processors.

* The alternative isolation level is `READ COMMITTED`. At this level data dependencies will not cause the processors to crash, but the execution is not guaranteed to be deterministic unless the sets of records that different processors read/write do not overlap.

* To avoid cross-chain data dependencies, use per-chain records for volatile data. E.g. if you track account balances across multiple chains you can avoid overlaps by storing the balance for each chain in a different table row.

  When you need to combine the records (e.g. get a total of all balances across chains) use a [custom resolver](../../reference/openreader/configuration/custom-resolvers) to do it on the GraphQL server side.

* It is OK to use cross-chain [entities](../../reference/schema-files/entities) to simplify aggregation. Just don't store any data in them:

  ```graphql theme={"system"}
  type Account @entity {
    id: ID! # evm address
    balances: [Balance!]! @derivedFrom(field: "account")
  }

  type Balance @entity {
    id: ID! # chainId + evm address
    account: Account!
    value: BigInt!
  }
  ```

## On [file-store](../other-data-destinations)

Ensure that you use a unique target folder for each processor.

## Example

A complete example is available [here](https://github.com/subsquid-labs/squid-multichain-template).
