Skip to main content

Configure web hosting to keep costs under control

  • Vercel and Railway provide convenient serverless platforms for hosting your application, abstracting away the logistics of web hosting relative to using a cloud provider directly. You may end up paying a premium for the convenience, especially at higher volumes.
  • AWS and other cloud providers offer more flexibility and commodity pricing.
  • Before choosing any service, check pricing and be aware that many providers offer loss-leader pricing on lower volumes, but then charge higher rates once you hit a certain threshold.
    • For example, suppose there is a $20 plan that includes 1 TB per month of data transfer, with $0.20 per GB beyond that. Do the math to note that the second TB (and onward) will cost $200. If the next tier up says “contact us”, don’t assume the next tier up will be charging $20 per TB.
    • If you are building a high-traffic app and you aren’t careful about serving static files more cheaply, it will be easy to exceed the loss-leader tier and pay much more than you expect.
  • For production deployments on AWS, consider:
    • Amazon S3 + CloudFront for static file hosting and CDN
    • AWS Lambda for serverless functions
    • Amazon ECS or EKS for containerized applications
    • Amazon RDS for database needs
    • This setup typically provides granular cost control and scalability for high-traffic applications.

Use a hardcoded value instead of eth_estimateGas call if gas usage is static

Many on-chain actions have a fixed gas cost. The simplest example is that a transfer of native tokens always costs 21,000 gas, but there are many others. This makes it unnecessary to call eth_estimateGas for each transaction. Use a hardcoded value instead, as suggested here. Eliminating an eth_estimateGas call substantially speeds up the user workflow in the wallet, and avoids a potential bad behavior in some wallets when eth_estimateGas reverts (discussed in the linked page).

Reduce eth_call latency by submitting multiple requests concurrently

Making multiple eth_call requests serially will introduce unnecessary latency due to multiple round trips to an RPC node. You can make many eth_calls concurrently, either by condensing them into a single eth_call or by submitting a batch of calls. Alternatively, you might find it better to switch to an indexer.

Condensing multiple eth_calls into one

  • Multicall: Multicall is a utility smart contract that allows you to aggregate multiple read requests (eth_call) into a single one. This is particularly effective for fetching data points like token balances, allowances, or contract parameters simultaneously. The standard Multicall3 contract is deployed at 0xcA11bde05977b3631167028862bE2a173976CA11 on both Monad Mainnet and Monad Testnet. Many libraries offer helper functions to simplify multicall usage, e.g. viem. Read more about Multicall3 here.
  • Custom Batching Contracts: For complex read patterns or scenarios not easily handled by the standard multicall contract, you can deploy a custom smart contract that aggregates the required data in a single function, which can then be invoked via a single eth_call.
Multicall executes calls serially as you can see from the code here. So while using multicall avoids multiple round trips to an RPC server, it is still inadvisable to put too many expensive calls into one multicall. A batch of calls (explained next) can be executed on the RPC in parallel.

Submitting a batch of calls

Most major libraries support batching multiple RPC requests into a single message. For example, viem handles Promise.all() on an array of promises by submitting them as a single batch:

Use indexers for read-heavy loads

If your application frequently queries historical events or derived state, consider using an indexer, as described next.

Use an indexer instead of repeatedly calling eth_getLogs to listen for your events

Below is a quickstart guide for the most popular data indexing solutions. Please view the indexer docs for more details.

Using Allium

See also: AlliumYou’ll need an Allium account, which you can request here.
  • Allium Explorer
    • Blockchain analytics platform that provides SQL-based access to historical blockchain data (blocks, transactions, logs, traces, and contracts).
    • You can create Explorer APIs through the GUI to query and analyze historical blockchain data. When creating a Query for an API here (using the New button), select Monad Mainnet or Monad Testnet from the chain list.
    • Relevant docs:
  • Allium Datastreams
    • Provides real-time blockchain data streams (including blocks, transactions, logs, traces, contracts, and balance snapshots) through Kafka, Pub/Sub, and Amazon SNS.
    • GUI to create new streams for onchain data. When creating a stream, select the relevant Monad Mainnet or Monad Testnet topics from the Select topics dropdown.
    • Relevant docs:
  • Allium Developers
    • Enables fetching wallet transaction activity and tracking balances (native, ERC20, ERC721, ERC1155).
    • For the request’s body, use monad_mainnet for Monad Mainnet or monad_testnet for Monad Testnet as the chain parameter.
    • Relevant docs:

Using Envio HyperIndex

  • Follow the quick start to create an indexer. In the config.yaml file, use network ID 10143 to select Monad testnet (used in the example below) or network ID 143 for Monad mainnet.
  • Example configuration
    • Sample config.yaml file
      config.yaml
    • Sample EventHandlers.ts
      EventHandlers.ts
  • Important: The rpc_config section under a network (check config.yaml sample) is optional and should only be configured if you experience issues with the default Envio setup. This configuration allows you to:
    • Use your own RPC endpoint
    • Configure block fetching parameters for better performance
  • Relevant docs:

Using GhostGraph

See also: Ghost

Using Goldsky

See also: Goldsky
  • Goldsky Subgraphs
    • To deploy a Goldsky subgraph follow this guide.
    • As the network identifier, use monad-mainnet for Monad Mainnet or monad-testnet for Monad Testnet. For subgraph configuration examples, refer to The Graph Protocol section below.
    • For information about querying Goldsky subgraphs, see the GraphQL API documentation.
  • Goldsky Mirror
    • Enables direct streaming of on-chain data to your database.
    • For the chain name in the dataset_name field when creating a source for a pipeline, use monad_mainnet for Monad Mainnet or monad_testnet for Monad Testnet (check below example)
    • Example pipeline.yaml config file
      pipeline.yaml
    • Relevant docs:

Using QuickNode Streams

  • On your QuickNode Dashboard, select Streams > Create Stream. In the create stream UI, select Monad Mainnet or Monad Testnet under Network. Alternatively, you can use the Streams REST API to create and manage streams—use monad-mainnet for Monad Mainnet or monad-testnet for Monad Testnet as the network identifier.
  • You can consume a Stream by choosing a destination during stream creation. Supported destinations include Webhooks, S3 buckets, and PostgreSQL databases. Learn more here.
  • Relevant docs:

Using The Graph’s Subgraph

See also: The Graph
  • Network ID: Use monad-mainnet for Monad Mainnet or monad-testnet for Monad Testnet
  • Example configuration
    • Sample subgraph.yaml file
      subgraph.yaml
    • Sample mappings.ts file
      mappings.ts
    • Sample schema.graphql file
      schema.graphql
  • Relevant docs:

Using thirdweb’s Insight API

See also: thirdweb
  • REST API offering a wide range of on-chain data, including events, blocks, transactions, token data (such as transfer transactions, balances, and token prices), contract details, and more.
  • Use chain ID 143 for Monad Mainnet or 10143 for Monad Testnet when constructing request URLs.
  • Relevant docs:

Manage nonces locally if sending multiple transactions in quick succession

This only applies if you are setting nonces manually. If you are delegating this to the wallet, no need to worry about this.
  • eth_getTransactionCount requires a network request. If you have multiple transactions from the same wallet in short succession, you should implement local nonce tracking.

Submit multiple transactions concurrently

If you are submitting a series of transactions, instead submitting sequentially, implement concurrent transaction submission for improved efficiency. Before:
After: