Why NestJS for Solana?
Most Solana tutorials stop at the frontend. But real dApps — DEXs, wallets, token launch platforms — need a robust backend for transaction simulation, indexing, caching, and orchestrating complex multi-step flows. NestJS is the best fit: it brings modular architecture, dependency injection, and first-class TypeScript support to Node.js.
At Cyber Vision we have shipped multiple production Solana backends with NestJS — from Compendex (a full DEX) to the Cilantro wallet infrastructure. This guide distills the architecture patterns that worked.
Prerequisites
- Node.js 18+
- NestJS CLI (
npm i -g @nestjs/cli) @solana/web3.jsv1.x- Basic understanding of Solana accounts and transactions
1. Scaffold the Project
nest new solana-backend
cd solana-backend
npm install @solana/web3.js @coral-xyz/anchor bs58NestJS generates a clean module structure out of the box. We will extend it with Solana-specific modules.
2. Project Structure
src/
├── app.module.ts
├── solana/
│ ├── solana.module.ts
│ ├── solana.service.ts # Core RPC connection + helpers
│ └── solana.health.ts # Custom health indicator
├── transactions/
│ ├── transactions.module.ts
│ ├── transactions.service.ts # Build, simulate, send
│ └── transactions.controller.ts
├── websocket/
│ ├── websocket.module.ts
│ └── websocket.gateway.ts # Real-time on-chain events
└── common/
├── decorators/
└── interceptors/
3. The Solana Service Provider
The core service wraps a Connection and exposes typed helper methods. Register it as a global provider so every module can inject it.
// src/solana/solana.service.ts
import { Injectable, OnModuleInit, Logger } from "@nestjs/common";
import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
@Injectable()
export class SolanaService implements OnModuleInit {
private readonly logger = new Logger(SolanaService.name);
private connection: Connection;
onModuleInit() {
const rpcUrl = process.env.SOLANA_RPC_URL || "https://api.devnet.solana.com";
this
// src/solana/solana.module.ts
import { Global, Module } from "@nestjs/common";
import { SolanaService } from "./solana.service";
@Global()
@Module({
providers: [SolanaService],
exports: [SolanaService],
})
export class SolanaModule {}Mark the module as @Global() so you don't need to import SolanaModule in every feature module. The SolanaService is available everywhere via dependency injection.
4. Transaction Simulation and Submission
Never send a transaction blind. Simulate first, check for errors, then submit.
// src/transactions/transactions.service.ts
import { Injectable, Logger } from "@nestjs/common";
import {
Transaction,
VersionedTransaction,
SendOptions,
} from "@solana/web3.js";
import { SolanaService } from "../solana/solana.service";
@Injectable()
export class TransactionsService {
private readonly logger = new Logger(TransactionsService.name);
constructor(private readonly solana: SolanaService) {}
async simulateTransaction(
5. RPC Health Checks
If your RPC goes down, everything breaks. Add a custom health indicator that NestJS exposes at /health.
// src/solana/solana.health.ts
import { Injectable } from "@nestjs/common";
import {
HealthIndicator,
HealthIndicatorResult,
HealthCheckError,
} from "@nestjs/terminus";
import { SolanaService } from "./solana.service";
@Injectable()
export class SolanaHealthIndicator extends HealthIndicator {
constructor(private readonly solana: SolanaService) {
super();
}
async isHealthy(key: string): Promise<HealthIndicatorResult
npm install @nestjs/terminusWire it into a health controller and your monitoring stack can poll /health to verify RPC connectivity.
6. WebSocket Gateway for On-Chain Events
Push real-time on-chain updates to connected frontends using NestJS WebSocket gateways.
// src/websocket/websocket.gateway.ts
import {
WebSocketGateway,
WebSocketServer,
OnGatewayInit,
OnGatewayConnection,
OnGatewayDisconnect,
} from "@nestjs/websockets";
import { Server, Socket } from "socket.io";
import { Logger } from "@nestjs/common";
import { PublicKey } from "@solana/web3.js";
import { SolanaService } from "../solana/solana.service";
@WebSocketGateway({ cors: true })
export class SolanaWebSocketGateway
implements
Solana RPC WebSocket subscriptions are limited. Most providers cap at 100-200 concurrent subscriptions. For high-throughput use cases, consider Geyser plugins or dedicated indexing services like Helius webhooks.
7. Environment Configuration
Use @nestjs/config for clean environment management:
// src/app.module.ts
import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { SolanaModule } from "./solana/solana.module";
import { TransactionsModule } from "./transactions/transactions.module";
import { WebSocketModule } from "./websocket/websocket.module";
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
SolanaModule,
TransactionsModule,
WebSocketModule,
],
})
export# .env
SOLANA_RPC_URL=https://api.devnet.solana.com
SOLANA_WS_URL=wss://api.devnet.solana.com
PORT=3001Architecture Summary
| Layer | Responsibility | Key Tech |
|---|---|---|
| SolanaModule | RPC connection, balance queries, account reads | @solana/web3.js |
| TransactionsModule | Build, simulate, submit transactions | Versioned transactions |
| WebSocketModule | Push real-time on-chain events to clients | Socket.io, onAccountChange |
| HealthModule | Monitor RPC availability | @nestjs/terminus |
| ConfigModule | Environment-based config | @nestjs/config |
Production Considerations
| Concern | Solution |
|---|---|
| RPC rate limits | Use a dedicated RPC provider (Helius, QuickNode) with higher limits |
| Connection pooling | Maintain a single Connection instance per cluster, reuse across requests |
| Error retry | Implement exponential backoff for sendRawTransaction failures |
| Caching | Cache getAccountInfo responses with TTL for hot accounts |
| Logging | Structured JSON logs with correlation IDs for transaction tracing |
| Testing | Mock SolanaService in unit tests, use localnet for integration tests |
Wrapping Up
NestJS gives your Solana dApp a proper backend: modular, testable, and production-ready. The patterns here — global Solana service, simulate-then-send, WebSocket gateway, health checks — are the foundation we use at Cyber Vision across every project from DEXs to wallet infrastructure.
Check out our Solana React Basics guide for the frontend side, and the Anchor coinflip tutorial for on-chain program development.