Python Backend for dApps: Async Architecture Overview

Synchronous solutions fail to handle the load when a blockchain project needs to update data and process transactions quickly. We build high-load Python backends for dApps using web3.py, FastAPI, and Celery, automating network interactions and background tasks. Our team delivers turnkey projects—from architecture to deployment and ongoing support.

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

Building dApp Backends with Python: Async Architecture

Imagine: a DeFi aggregator needs to update prices from 20 pools every 5 minutes, calculate impermanent loss, and send transactions with minimal slippage. Synchronous Flask won't cut it — the blockchain produces a block every 12–15 seconds, and each HTTP request waits for an RPC response. Python with an async stack solves this: web3.py for the blockchain, FastAPI for the API, Celery for background tasks. Over a decade of experience, we've delivered 10+ such projects: from NFT marketplaces to DeFi aggregators with APY calculators.

web3.py documentation provides a smooth interface to interact with Ethereum nodes.

How web3.py Simplifies Blockchain Interaction

web3.py is a mature library for working with EVM networks. Key pain points: checksum address validation and PoA middleware. Without Web3.to_checksum_address(), any call to an external source will throw an error. For Polygon and BNB Chain, we always attach geth_poa_middleware. Example setup:

from web3 import Web3
from web3.middleware import geth_poa_middleware

w3 = Web3(Web3.HTTPProvider("https://eth-mainnet.g.alchemy.com/v2/KEY"))
w3.middleware_onion.inject(geth_poa_middleware, layer=0)

balance = w3.eth.get_balance("0xChecksumAddress")

contract = w3.eth.contract(address=checksum_address, abi=ABI)
result = contract.functions.balanceOf(address).call()

How Asynchronicity and Celery Solve Performance Issues

Synchronous blockchain calls block the event loop. We use FastAPI + async web3, and offload background tasks to Celery. Async web3 is 10x faster than synchronous requests, boosting throughput from ~50 to 500+ req/s. Celery tasks handle long-running operations: sending transactions, indexing events, syncing prices. Example task with retry:

from celery import Celery
from celery.schedules import crontab

celery_app = Celery("dapp", broker="redis://localhost:6379/0")

@celery_app.task(bind=True, max_retries=3)
def send_transaction(self, contract_address, function_name, args):
    try:
        contract = w3.eth.contract(address=contract_address, abi=ABI)
        tx_hash = contract.functions[function_name](*args).transact({
            "from": hot_wallet.address,
            "gas": 200000
        })
        return {"tx_hash": tx_hash.hex(), "status": "pending"}
    except Exception as exc:
        raise self.retry(exc=exc, countdown=30)

celery_app.conf.beat_schedule = {
    "sync-prices": {
        "task": "tasks.sync_token_prices",
        "schedule": crontab(minute="*/5")
    }
}

Key dApp Backend Challenges

Nonce management. When sending transactions in parallel, two workers may read the same nonce — one transaction gets stuck. Solution: Redis locks with TTL or a nonce pool. Gas optimization. Every extra eth_call or eth_sendTransaction costs money. Caching data at the API layer cuts costs by 30–40%, saving approximately $500/month on infrastructure for medium-scale projects. Event indexing. WebSocket subscriptions are unreliable in production — we use Alchemy Notify + Celery tasks for resync on failures.

More on nonce managementNonce is a transaction counter from one address. Without locking, two workers may send the same nonce. We use Redis locks: before sending, a worker grabs a lock on the address, sends the transaction, and releases it. TTL ensures the lock doesn't persist if the worker crashes.

Our Stack and Code Examples

Feature Synchronous (Flask + requests) Async (FastAPI + async web3)
Throughput ~50 req/s 500+ req/s
Event loop blocking Yes No
Celery Required Required, but less critical
Debug complexity Low Medium
Use cases Simple proxies, low load High-load DeFi, real-time

FastAPI with Pydantic v2 for validation:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, validator
import re

class TransactionRequest(BaseModel):
    address: str
    amount: str

    @validator("address")
    def validate_eth_address(cls, v):
        if not re.match(r"^0x[a-fA-F0-9]{40}$", v):
            raise ValueError("Invalid Ethereum address")
        return Web3.to_checksum_address(v)

app = FastAPI()

@app.get("/api/balance/{address}")
async def get_balance(address: str):
    try:
        checksum = Web3.to_checksum_address(address)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid address")
    balance_wei = w3.eth.get_balance(checksum)
    return {
        "address": checksum,
        "balance_eth": Web3.from_wei(balance_wei, "ether"),
        "balance_wei": str(balance_wei)
    }

SQLAlchemy + PostgreSQL storing wei as string:

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped
from datetime import datetime

class Base(DeclarativeBase):
    pass

class Transaction(Base):
    __tablename__ = "transactions"
    id: Mapped[int] = mapped_column(primary_key=True)
    tx_hash: Mapped[str] = mapped_column(unique=True, index=True)
    from_address: Mapped[str] = mapped_column(index=True)
    to_address: Mapped[str] = mapped_column(index=True)
    value_wei: Mapped[str]  # string to avoid precision loss
    block_number: Mapped[int] = mapped_column(index=True)
    timestamp: Mapped[datetime]
    status: Mapped[str]

Our Process

  1. Analysis. We study smart contracts, API requirements, business logic. Create a technical specification.
  2. Design. Define architecture: DB structure, API methods, Celery tasks, signing scheme.
  3. Implementation. Write code, cover with tests (pytest), integrate with the blockchain.
  4. Testing. Deploy on testnet, verify scenarios: transaction sending, event handling, recovery after failures.
  5. Deployment. Deploy to production with Docker, set up monitoring (Grafana, Loki).

Timeline Estimates

Stage Duration
Base architecture, web3.py clients, REST API (read-only), PostgreSQL 1 week
Celery tasks, indexer, SIWE authentication, transaction signing 1 week
Complex business logic (analytics, ML) from 3 days

Full backend — from 1.5 to 2 weeks. Pricing is determined individually (typically starting at $8,000). This architecture reduces infrastructure costs by 30–40%, saving over $2,000 per year for mid-sized projects.

Common Mistakes in Python dApp Backend Development

  • Forgetting nonce management. Without synchronization, parallel requests cause stuck transactions.
  • Using Decimal for wei. Store as string to avoid precision loss.
  • Not adding middleware for PoA networks. Otherwise get_block throws an error.
  • Synchronous requests in API. They block the event loop, cutting throughput by 10x.

What You Get

  • Architecture tailored to your business logic.
  • REST API with OpenAPI documentation.
  • Event indexer writing to PostgreSQL.
  • Background tasks: transaction sending, price sync, health checks.
  • Secure signing with hot wallet or integration with Vault/AWS KMS.
  • Docker containerization and deployment documentation.
  • 3-month code warranty and post-delivery support.

We build dApp backends in Python using web3.py, FastAPI, and Celery. Contact us for a consultation — we'll help choose the architecture and estimate timelines. Request your dApp backend development today.