dApp Backend on Node.js: Build from Scratch

When on-chain functionality is not enough, a dApp requires a reliable server layer: a private RPC proxy, SIWE authentication, event indexing, or gasless transactions. We build dApp backends on Node.js from scratch, delivering turnkey projects from architecture to deployment. Our team handles the entire cycle and provides ongoing support, so you get a scalable solution without missed deadlines.

Blockchain Development Services

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1335
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1293
  • B2B Advance company logo design
    B2B Advance company logo design
    738
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1031
  • AIDER company logo development
    AIDER company logo development
    978
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1087

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.