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

# Best Practices

> Production tips for Yellowstone gRPC on Solana — filter subscriptions, handle reconnects, manage backpressure, and tune commitment levels for low latency.

## Network Latency Optimization

### Minimize Your Ping

Latency starts at the network level. No matter how optimized your code is, the speed of light remains the ultimate bottleneck. The single most impactful action you can take to minimize latency is to achieve geographical **co-location** with the gRPC endpoint.

<Warning>
  **Target: 0-1 milliseconds network latency**

  Aim for sub-millisecond ping between your client application and the gRPC endpoint.
</Warning>

### Recommended Data Centers

Co-locate your infrastructure in these data centers for optimal performance:

<Tabs>
  <Tab title="Europe">
    **Providers:** Cherry Servers, Latitude, velia.net, hostkey.com, Teraswitch

    **Endpoint:** `https://grpc.solanatracker.io`
  </Tab>

  <Tab title="North America">
    **Providers:** Latitude, velia.net, hostkey.com, Teraswitch, WebNX

    **Endpoint:** `https://grpc-us.solanatracker.io`
  </Tab>
</Tabs>

### Measuring Latency

It's possible to achieve **1-2 ms** latency without co-locating if you're in the same region. Use these tools to measure your latency:

```bash theme={null}
# Test ping to EU endpoint
ping grpc.solanatracker.io

# Test ping to US endpoint
ping grpc-us.solanatracker.io

# Detailed route analysis
mtr grpc.solanatracker.io
```

<Note>
  **Latency Targets:**

  * **Excellent:** 0-1ms (co-located)
  * **Good:** 1-2ms (same region)
  * **Acceptable:** 2-5ms (nearby region)
  * **Poor:** >5ms (consider relocating)
</Note>

## Connection Management

### Distribute Load Across Multiple Clients

Streaming multiple high-load addresses (e.g., Meteora DLMM, Pump.fun, DEX programs) in a single subscription can quickly overwhelm a single client connection.

**Problems with single client:**

* Message backlog at network layer
* Single consumer thread bottleneck
* Client may disconnect due to unmanageable backlog

<Warning>
  **Best Practice:** Split high-load addresses across multiple gRPC clients and distribute processing across separate CPU cores/threads.
</Warning>

### When to Use Multiple Clients

<Tabs>
  <Tab title="High-Load Programs">
    **Use separate clients for:**

    * DEX programs (Raydium, Jupiter, Orca)
    * Pump.fun program
    * Meteora DLMM
    * Popular lending protocols

    ```typescript theme={null}
    // Separate client for each high-volume program
    const raydiumClient = new Client(endpoint, token);
    const jupiterClient = new Client(endpoint, token);
    const pumpfunClient = new Client(endpoint, token);

    // Process on different threads/cores
    await Promise.all([
      processRaydiumStream(raydiumClient),
      processJupiterStream(jupiterClient),
      processPumpfunStream(pumpfunClient)
    ]);
    ```
  </Tab>

  <Tab title="Moderate-Load Addresses">
    **Combine in single client:**

    * Individual tokens
    * Liquidity pools
    * User wallets
    * Low-activity programs

    ```typescript theme={null}
    // Single client for multiple moderate-load addresses
    const subscribeRequest: SubscribeRequest = {
      accounts: {
        multipleAddresses: {
          account: [
            "token1Address",
            "token2Address",
            "poolAddress",
            "walletAddress"
          ],
          owner: [],
          filters: []
        }
      },
      commitment: CommitmentLevel.CONFIRMED
    };
    ```
  </Tab>
</Tabs>

### Connection Efficiency

Over-fragmenting your connections for moderate-load addresses can quickly hit connection limits.

<Note>
  **Best Practice:** Don't create a new connection for each token, pool, or wallet address. Combine them in a single subscribe request.
</Note>

Example of efficient connection planning:

```typescript theme={null}
class ConnectionManager {
  private highLoadClients: Map<string, Client> = new Map();
  private moderateLoadAddresses: string[] = [];

  async initialize() {
    // Separate clients for high-load programs
    this.highLoadClients.set('raydium', new Client(endpoint, token));
    this.highLoadClients.set('jupiter', new Client(endpoint, token));
    this.highLoadClients.set('pumpfun', new Client(endpoint, token));

    // Track moderate-load addresses together
    this.moderateLoadAddresses = [];
  }

  async addModerateLoadAddress(address: string) {
    this.moderateLoadAddresses.push(address);

    // Send this request on your active stream, or reconnect with it.
    return {
      accounts: {
        moderate: {
          account: this.moderateLoadAddresses,
          owner: [],
          filters: []
        }
      }
    };
  }
}
```

When your address list changes, send an updated subscribe request on the active stream if your client supports it. If not, close the stream and reconnect with the new combined request.

## Client Configuration

### Expand Max Message Size

Yellowstone gRPC clients have a default maximum size of **4 MB (4194304 bytes)** for incoming messages. When streaming account updates or block updates, you can hit this limit.

<Warning>
  **Required:** Configure your gRPC client to avoid hitting the 4 MB message limit.
</Warning>

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const client = new Client(
      "https://grpc.solanatracker.io",
      "your-x-token",
      {
        "grpc.max_receive_message_length": 1024 * 1024 * 1024 // 1 GB
      }
    );
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    async fn connect(&self) -> anyhow::Result<GeyserGrpcClient<impl Interceptor>> {
        GeyserGrpcClient::build_from_shared(self.grpc_url.clone())?
            .x_token(Some(self.grpc_token.clone()))?
            .connect_timeout(Duration::from_secs(10))
            .timeout(Duration::from_secs(10))
            .tls_config(ClientTlsConfig::new().with_native_roots())?
            .max_decoding_message_size(1024 * 1024 * 1024) // 1 GB
            .connect()
            .await
            .map_err(Into::into)
    }
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    conn, err := grpc.Dial(
        "grpc.solanatracker.io:443",
        grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")),
        grpc.WithDefaultCallOptions(
            grpc.MaxCallRecvMsgSize(1024 * 1024 * 1024), // 1 GB
            grpc.MaxCallSendMsgSize(1024 * 1024 * 1024),
        ),
    )
    ```
  </Tab>
</Tabs>

### Keepalive Configuration

Configure keepalive to maintain persistent connections:

```typescript theme={null}
const client = new Client(
  endpoint,
  token,
  {
    "grpc.keepalive_time_ms": 30000,        // Send keepalive every 30s
    "grpc.keepalive_timeout_ms": 5000,      // Wait 5s for keepalive response
    "grpc.keepalive_permit_without_calls": 1 // Allow keepalive without active calls
  }
);
```

### Connection Timeouts

Set reasonable timeout values:

```typescript theme={null}
{
  "grpc.initial_reconnect_backoff_ms": 1000,  // Start with 1s backoff
  "grpc.max_reconnect_backoff_ms": 30000,     // Max 30s backoff
  "grpc.min_reconnect_backoff_ms": 1000       // Min 1s backoff
}
```

## Processing Optimization

### Asynchronous Processing

Decouple I/O (receiving messages) from CPU-bound work (deserializing, filtering, business logic):

```typescript theme={null}
class StreamProcessor {
  private messageQueue: Array<any> = [];
  private processing = false;

  async handleMessage(data: any) {
    // Add to queue (fast)
    this.messageQueue.push(data);
    
    // Process asynchronously
    if (!this.processing) {
      this.processQueue();
    }
  }

  private async processQueue() {
    this.processing = true;
    
    while (this.messageQueue.length > 0) {
      const message = this.messageQueue.shift();
      
      // CPU-intensive processing
      await this.parseAndProcess(message);
    }
    
    this.processing = false;
  }

  private async parseAndProcess(message: any) {
    // Your parsing and business logic here
  }
}
```

### Worker Thread Distribution

For extremely high-volume streams, distribute processing across worker threads:

```typescript theme={null}
import { Worker } from 'worker_threads';

class MultiThreadProcessor {
  private workers: Worker[] = [];
  private roundRobin = 0;

  constructor(numWorkers: number = 4) {
    for (let i = 0; i < numWorkers; i++) {
      this.workers.push(new Worker('./processor-worker.js'));
    }
  }

  async handleMessage(data: any) {
    // Distribute to workers in round-robin fashion
    const worker = this.workers[this.roundRobin];
    worker.postMessage(data);
    
    this.roundRobin = (this.roundRobin + 1) % this.workers.length;
  }
}
```

## Error Handling

### Implement Exponential Backoff

```typescript theme={null}
class ResilientStreamManager {
  private reconnectAttempts = 0;
  private readonly maxReconnectAttempts = 10;
  private readonly baseReconnectDelay = 1000;

  private async reconnect(subscribeRequest: SubscribeRequest): Promise<void> {
    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.error("Max reconnection attempts reached.");
      return;
    }

    this.reconnectAttempts++;
    const delay = this.baseReconnectDelay * Math.pow(2, Math.min(this.reconnectAttempts - 1, 5));
    
    console.log(`Reconnect attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts} in ${delay}ms...`);
    
    setTimeout(() => {
      this.connect(subscribeRequest).catch(console.error);
    }, delay);
  }
}
```

### Handle Stream Errors Gracefully

```typescript theme={null}
stream.on("error", (error) => {
  console.error("Stream error:", error);
  
  // Log error details
  logErrorToMonitoring(error);
  
  // Don't crash - attempt to reconnect
  this.handleDisconnect(subscribeRequest);
});

stream.on("end", () => {
  console.log("Stream ended, reconnecting...");
  this.handleDisconnect(subscribeRequest);
});
```

## Monitoring & Observability

### Track Key Metrics

```typescript theme={null}
class StreamMetrics {
  private messagesReceived = 0;
  private messagesProcessed = 0;
  private errors = 0;
  private lastReportTime = Date.now();

  recordMessage() {
    this.messagesReceived++;
  }

  recordProcessed() {
    this.messagesProcessed++;
  }

  recordError() {
    this.errors++;
  }

  report() {
    const now = Date.now();
    const elapsed = (now - this.lastReportTime) / 1000;
    
    console.log(`\n=== Stream Metrics (${elapsed.toFixed(1)}s) ===`);
    console.log(`  Messages Received: ${this.messagesReceived}`);
    console.log(`  Messages Processed: ${this.messagesProcessed}`);
    console.log(`  Processing Rate: ${(this.messagesProcessed / elapsed).toFixed(2)}/sec`);
    console.log(`  Errors: ${this.errors}`);
    console.log(`  Backlog: ${this.messagesReceived - this.messagesProcessed}`);
    
    this.lastReportTime = now;
  }
}
```

### Alert on Anomalies

```typescript theme={null}
class AnomalyDetector {
  private readonly backlogThreshold = 1000;
  private readonly errorRateThreshold = 0.01; // 1%

  checkHealth(metrics: StreamMetrics) {
    const backlog = metrics.messagesReceived - metrics.messagesProcessed;
    
    if (backlog > this.backlogThreshold) {
      this.alert(`High backlog: ${backlog} messages`);
    }
    
    const errorRate = metrics.errors / metrics.messagesReceived;
    if (errorRate > this.errorRateThreshold) {
      this.alert(`High error rate: ${(errorRate * 100).toFixed(2)}%`);
    }
  }

  private alert(message: string) {
    console.error(`[ALERT] ${message}`);
    // Send to your monitoring system
  }
}
```

## Security Best Practices

### Protect Your Credentials

<Warning>
  **Never commit credentials to version control!**
</Warning>

```bash theme={null}
# .env file (add to .gitignore)
GRPC_ENDPOINT=https://grpc.solanatracker.io
GRPC_X_TOKEN=your-secret-token

# .gitignore
.env
*.env
.env.*
```

### Rotate Tokens Regularly

```typescript theme={null}
class TokenRotationManager {
  private currentToken: string;
  private nextToken?: string;

  async rotateToken(newToken: string) {
    this.nextToken = newToken;
    
    // Gracefully switch to new token
    await this.reconnectWithNewToken();
    
    this.currentToken = this.nextToken;
    this.nextToken = undefined;
  }

  private async reconnectWithNewToken() {
    // Disconnect current stream
    this.disconnect();
    
    // Connect with new token
    await this.connect(this.nextToken!);
  }
}
```

## Performance Checklist

<Note>
  **Production Deployment Checklist:**

  * [ ] Co-locate in recommended data center (0-1ms latency)
  * [ ] Separate high-load programs into different clients
  * [ ] Configure max message size to 1GB
  * [ ] Implement keepalive (30s interval)
  * [ ] Use asynchronous processing
  * [ ] Implement exponential backoff reconnection
  * [ ] Monitor message rates and backlog
  * [ ] Set up error alerting
  * [ ] Use environment variables for credentials
  * [ ] Implement token rotation mechanism
  * [ ] Log metrics for analysis
  * [ ] Test failover scenarios
</Note>

## Common Pitfalls

<Accordion title="Processing Blocking Network I/O">
  **Problem:** Slow processing logic blocks receiving new messages

  **Solution:** Decouple message receipt from processing using queues and async processing
</Accordion>

<Accordion title="Too Many Connections">
  **Problem:** Creating separate connection for each address

  **Solution:** Combine moderate-load addresses in single subscription
</Accordion>

<Accordion title="Insufficient Error Handling">
  **Problem:** Stream crashes on errors without recovery

  **Solution:** Implement comprehensive error handling with automatic reconnection
</Accordion>

<Accordion title="No Monitoring">
  **Problem:** Can't diagnose performance issues or failures

  **Solution:** Implement metrics tracking and alerting from day one
</Accordion>

## Next Steps

<CardGroup cols={2}>
  <Card title="Account Monitoring" icon="user" href="/yellowstone-grpc/account-monitoring">
    Implement efficient account streaming
  </Card>

  <Card title="Transaction Monitoring" icon="receipt" href="/yellowstone-grpc/transaction-monitoring">
    Optimize transaction stream processing
  </Card>

  <Card title="Pump.fun Examples" icon="chart-line" href="/yellowstone-grpc/examples/pumpfun-transactions">
    See best practices in action
  </Card>
</CardGroup>
