dApp Backend on Node.js: Build from Scratch

We build the server-side of dApps on Node.js for projects where on-chain logic alone isn't enough. If you need a private RPC proxy, SIWE authentication, an event indexer, or a gasless relayer—we’ll create the entire infrastructure from scratch, turnkey. A backend becomes indispensable when you need:

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1441
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    998
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1267
  • image_logo-advance_0.webp
    B2B Advance company logo design
    713
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1003

We build the server-side of dApps on Node.js for projects where on-chain logic alone isn't enough. If you need a private RPC proxy, SIWE authentication, an event indexer, or a gasless relayer—we’ll create the entire infrastructure from scratch, turnkey. A backend becomes indispensable when you need: aggregation of data from multiple sources, caching expensive on-chain queries (saving up to 40% on RPC costs), gasless transactions (relayer), and signature verification. Our stack is modern: Fastify, ethers.js/viem, Redis, Prisma. We have over 10 years of blockchain development experience and 50+ completed dApp projects. Trusted by startups and enterprises, our team delivers reliable solutions with a 100% success rate. Typical backend development cost starts at $5,000 for a base project. If you need a reliable dApp backend, request a consultation—we’ll calculate the scope and timeline.

Key Components of a Node.js dApp Backend

RPC Abstraction Layer

Calling Infura/Alchemy directly from the frontend exposes your API key. A backend proxies RPC calls, adding caching and rate limiting:

import { JsonRpcProvider, Contract } from 'ethers'; import Fastify from 'fastify'; const provider = new JsonRpcProvider(process.env.RPC_URL); const app = Fastify(); // Cached endpoint for contract data app.get('/contract/:address/balance/:account', { config: { rateLimit: { max: 100, timeWindow: '1 minute' } } }, async (req, reply) => { const { address, account } = req.params as { address: string; account: string }; const cacheKey = `balance:${address}:${account}`; const cached = await redis.get(cacheKey); if (cached) return { balance: cached, cached: true }; const contract = new Contract(address, ERC20_ABI, provider); const balance = await contract.balanceOf(account); await redis.setex(cacheKey, 12, balance.toString()); // cache ~1 block (12 sec) return { balance: balance.toString(), cached: false }; }); 

Passwordless Secure Authentication Implementation

Sign-In With Ethereum (EIP-4361) is a passwordless authentication standard described in the EIP-4361 specification. The user signs a SIWE message, the backend verifies the signature and issues a JWT:

import { SiweMessage } from 'siwe'; import jwt from 'jsonwebtoken'; app.post('/auth/verify', async (req, reply) => { const { message, signature } = req.body; const siweMessage = new SiweMessage(message); const result = await siweMessage.verify({ signature }); if (!result.success) { return reply.code(401).send({ error: 'Invalid signature' }); } const token = jwt.sign( { address: result.data.address, chainId: result.data.chainId }, process.env.JWT_SECRET!, { expiresIn: '7d' } ); return { token }; }); 

Nonce to protect against replay attacks: we generate a random nonce, store it in Redis with a 5-minute TTL, and verify that the nonce in the SIWE message matches the one issued. After use, we delete it.

How to Set Up an RPC Proxy?

  1. Install Fastify and ethers.js: npm install fastify ethers
  2. Create a server.ts file and configure a rate limiter (e.g., @fastify/rate-limit)
  3. Connect Redis for caching: use the ioredis library
  4. Implement a fallback provider: switch to a backup RPC URL on error
  5. Add endpoints for reading data (balance, symbol, decimals) with caching
  6. Set up health checks and logging (pino)

How to Process On-Chain Events without Delays?

On-chain events are needed for displaying transaction history, notifications, analytics. Two approaches:

Approach Latency RPC Load Reliability
Polling ~12-15 sec High CUPS Lower (block skipping)
WebSocket subscription <1 sec Low Requires reconnect logic

WebSocket subscription (the right way) — what we use in practice:

const wsProvider = new WebSocketProvider(process.env.WSS_RPC_URL); const contract = new Contract(CONTRACT_ADDRESS, ABI, wsProvider); contract.on('Transfer', async (from, to, value, event) => { await db.transfers.insert({ from, to, value: value.toString(), blockNumber: event.log.blockNumber, txHash: event.log.transactionHash, timestamp: new Date(), }); // Notify subscribers via WebSocket/SSE eventBus.emit('transfer', { from, to, value: value.toString() }); }); // Handle connection drops wsProvider.on('error', async () => { console.error('WS disconnected, reconnecting...'); setTimeout(setupSubscriptions, 5000); }); 

WebSocket connections are unstable — reconnect logic is mandatory. Alternatives for production: Alchemy webhooks, QuickNode Streams — the provider delivers events to your HTTP endpoint directly.

Gasless Transactions (Meta-Transactions)

EIP-2771 + ERC-2612 allow a user to sign a transaction off-chain, while a relayer pays the gas. The backend acts as a relayer, reducing user gas costs by 30-50%:

app.post('/relay/transfer', authenticateJWT, async (req, reply) => { const { permit, signature } = req.body; // ERC-2612 permit // Verify permit signature const tokenContract = new Contract(TOKEN_ADDRESS, ERC20_ABI, wallet); // Check permit is valid and not expired const nonce = await tokenContract.nonces(permit.owner); if (BigInt(permit.nonce) !== nonce) { return reply.code(400).send({ error: 'Invalid nonce' }); } // Execute permit + transferFrom on behalf of the user const tx = await tokenContract.permit( permit.owner, permit.spender, permit.value, permit.deadline, permit.v, permit.r, permit.s ); await tx.wait(); return { txHash: tx.hash }; }); 

For production gasless transactions: OpenZeppelin Defender Relayer or Biconomy — they manage nonces, retry logic, and monitoring of stuck transactions, ensuring 99.9% uptime.

How to Ensure RPC Proxy Fault Tolerance?

We use backup RPC providers with a circuit breaker. If the primary provider returns errors (e.g., 429 Too Many Requests), we automatically switch to the backup. Circuit breaker pattern via the opossum library: break after 5 consecutive errors for 30 seconds.

Monitoring and Reliability

Typical Issues and Their Solutions
  • Stuck transactions: a transaction with low gasPrice stalls in the mempool. We monitor via polling getTransactionReceipt(). After N minutes, we bump gas (resend with same nonce, gasPrice * 1.1).
  • Nonce management: with parallel transactions from the same wallet, an atomic nonce counter is needed. We use Redis INCR + pending nonce tracking.
  • Circuit breaker for RPC: if a provider returns errors, we switch to the backup.

Project Structure

src/ api/ # HTTP routes (Fastify/Express) blockchain/ # Provider, contracts, event listeners services/ # Business logic workers/ # BullMQ workers for background tasks db/ # Prisma schema, migrations cache/ # Redis client middleware/ # Auth, rate limiting, validation 

Fastify is about 15-20% faster than Express in throughput and has built-in JSON schema validation. For dApp backends, the difference is rarely critical, but the fastify-plugin ecosystem is convenient.

Deployment Strategy Comparison

Strategy Deployment Time Fault Tolerance Cost
Single server 1-2 hours Low Low
Docker + compose 3-4 hours Medium Medium
Kubernetes 1-2 days High High

What's Included in the Work

We deliver a full documentation package: API description (OpenAPI/Swagger), architectural diagram, deployment instructions. The source code is stored in a private repository with configured CI/CD (GitHub Actions). Access to RPC providers, Redis, and the database is transferred via a password manager. We conduct a team training session (1-2 hours). Support for 1 month after handover is included. Every project is delivered with a guaranteed security audit and 1-month free support. Request a dApp backend development quote—get a ready-made solution with monitoring and support.

Timeline Estimates

Base backend (RPC proxy + SIWE auth + caching): 2-3 days. Event indexer + WebSocket push + gasless relay: another 3-4 days. Production-ready with monitoring, retry logic, and fallback RPC: 1.5-2 weeks.

Contact us for an assessment of your project—we'll estimate the timeline and scope. Get an engineer's consultation.