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

# Network Transformers

> Customize the network list before it's used throughout the SDK

Rewrite, filter, reorder, or add networks before they're used by the SDK. Set once during initialization with the `transformers.networksData` callback, applies to all operations (balance fetching, transactions, RPC client creation).

<Accordion title="New to web3?">
  **What is an RPC?** An RPC (remote procedure call) endpoint is the URL your app uses to read from and write to a blockchain (e.g. send transactions, read balances). The SDK needs at least one RPC URL per network.

  **Why set your own?** You might set custom RPC URLs for rate limits, reliability, or to use a provider you already use (e.g. Alchemy, Infura). If you don't set them, the SDK uses defaults from the Dynamic dashboard.

  **When can I skip this?** If you're fine with the dashboard defaults and don't need to customize networks, you don't need to use network transformers. Only use this page when you want to override RPC URLs, restrict which networks are available, control the default network, or add a custom network.
</Accordion>

## Prerequisites

Before this: create and initialize a Dynamic client (see [Creating a Dynamic Client](/docs/javascript/reference/client/create-dynamic-client), [Initializing the Dynamic Client](/docs/javascript/reference/client/initialize-dynamic-client)). You also need `@dynamic-labs-sdk/client` installed; RPC provider API keys are optional.

## Quick Start

The `networksData` transformer receives the full list of networks from your project settings and returns the list the SDK should use. Return a new array — filter it, reorder it, map over it, or append to it.

```javascript theme={"system"}
import { createDynamicClient } from '@dynamic-labs-sdk/client';

const dynamicClient = createDynamicClient({
  environmentId: 'YOUR_ENVIRONMENT_ID',
  transformers: {
    networksData: (networksData) =>
      networksData.map((network) => {
        if (network.networkId === '1') {
          return {
            ...network,
            rpcUrls: {
              http: ['https://eth-mainnet.g.alchemy.com/v2/YOUR-KEY'],
            },
          };
        }
        return network;
      }),
  },
});
```

## The default network

The first network of a chain is the default for wallets with no saved network selection — so ordering controls the fresh-install default. Filtering or reordering the list also changes which network a wallet starts on.

```javascript theme={"system"}
transformers: {
  // Restrict the SDK to a single network and make it the default.
  networksData: (networksData) =>
    networksData.filter((network) => network.networkId === '988'),
}
```

## Common Patterns

**Override RPC URLs for multiple networks:**

```javascript theme={"system"}
const RPC_URLS = {
  '1': process.env.ETHEREUM_RPC_URL,
  '137': process.env.POLYGON_RPC_URL,
  '8453': process.env.BASE_RPC_URL,
};

transformers: {
  networksData: (networksData) =>
    networksData.map((network) => {
      const url = RPC_URLS[network.networkId];
      if (!url) {
        return network;
      }
      return { ...network, rpcUrls: { http: [url] } };
    }),
}
```

**Add fallback URLs:**

```javascript theme={"system"}
transformers: {
  networksData: (networksData) =>
    networksData.map((network) => ({
      ...network,
      rpcUrls: {
        http: [`https://primary.com/${process.env.KEY}`, ...network.rpcUrls.http],
      },
    })),
}
```

**Reorder to set the default, then customize:**

```javascript theme={"system"}
transformers: {
  networksData: (networksData) => {
    // Put Base first so it's the default network.
    const base = networksData.filter((network) => network.networkId === '8453');
    const rest = networksData.filter((network) => network.networkId !== '8453');
    return [...base, ...rest];
  },
}
```

**Environment-based RPC URLs:**

```javascript theme={"system"}
const getRpcUrl = (network) => {
  if (process.env.NODE_ENV === 'development') return 'http://localhost:8545';
  if (process.env.NODE_ENV === 'staging') return 'https://sepolia-rpc.com';
  return `https://mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`;
};

transformers: {
  networksData: (networksData) =>
    networksData.map((network) => ({
      ...network,
      rpcUrls: { http: [getRpcUrl(network)] },
    })),
}
```

## NetworkData shape

Each `network` in the list has the following fields:

| Field               | Type                                                 | Description                                                              |
| ------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------ |
| `networkId`         | `string`                                             | Unique identifier for the network (chain ID for EVM, cluster for Solana) |
| `name`              | `string`                                             | Human-readable network name                                              |
| `rpcUrls`           | `{ http: string[] }`                                 | List of RPC endpoints for the network                                    |
| `nativeCurrency`    | `{ name: string, symbol: string, decimals: number }` | Native token details                                                     |
| `blockExplorerUrls` | `string[]`                                           | Block explorer URLs                                                      |
| `chainName`         | `string`                                             | The blockchain family (e.g., `'ETH'`, `'SOL'`, `'SUI'`)                  |

When you rewrite a network, spread the original and override only what you need. Extra properties beyond this shape are preserved.

## Network IDs

EVM networks use chain IDs: `'1'` (Ethereum), `'137'` (Polygon), `'8453'` (Base), `'42161'` (Arbitrum), `'10'` (Optimism), `'11155111'` (Sepolia)

Solana networks use cluster names: `'mainnet-beta'`, `'devnet'`, `'testnet'`

The transformer receives all chains — EVM, Solana, Sui, and others enabled in your project — in one list.

## Provider Examples

**Alchemy:**

```javascript theme={"system"}
const KEY = process.env.ALCHEMY_KEY;
const RPC_URLS = {
  '1': `https://eth-mainnet.g.alchemy.com/v2/${KEY}`,
  '137': `https://polygon-mainnet.g.alchemy.com/v2/${KEY}`,
};
```

**Infura:**

```javascript theme={"system"}
const KEY = process.env.INFURA_KEY;
const RPC_URLS = {
  '1': `https://mainnet.infura.io/v3/${KEY}`,
  '137': `https://polygon-mainnet.infura.io/v3/${KEY}`,
};
```

## Error handling

The callback's output is validated at runtime, but validation never blocks your app:

* If the callback returns malformed network data, the SDK logs an error and still uses the returned list. Operations relying on the invalid fields may misbehave.
* If the callback throws, the SDK logs an error and falls back to the untransformed list (restoring the untransformed default network).

Errors are reported through the client's logger at `error` level. If you provide a custom logger, forward `error` calls to see them.

## Rules

* Always return a valid `NetworkData[]` list
* Keep the callback pure and synchronous (no async/await, no side effects)
* Use environment variables for API keys
* The callback runs on network reads, starting after project settings load

## Migrating from `networkData`

<Info>
  The per-item `transformers.networkData` callback is deprecated in favor of `transformers.networksData`. It still works and the two compose — `networkData` runs on each network first, then `networksData` receives the resulting list — but `networkData` can only rewrite individual networks; it can't filter, reorder, or add networks or control the default. Move your logic into `networksData` by wrapping it in `networksData.map(...)`.
</Info>

```javascript theme={"system"}
// Before
transformers: {
  networkData: (network) => ({ ...network, rpcUrls: { http: [url] } }),
}

// After
transformers: {
  networksData: (networksData) =>
    networksData.map((network) => ({ ...network, rpcUrls: { http: [url] } })),
}
```

## React

Network transformers are configured at client creation time, so they live in the same module-level file as your `createDynamicClient` call. No React-specific wiring needed — the transformer runs during initialization before any component renders.

## Related

* [createDynamicClient](/docs/javascript/reference/client/create-dynamic-client)
