Most teams pick an Ethereum RPC endpoint the way they pick a placeholder logo. It works on day one, so it quietly becomes “the way we connect.”
Then the first real spike hits. A dashboard refresh turns into a thundering herd of eth_call requests. A log query stretches across thousands of blocks. Rate limits appear, retries pile up, and suddenly your “web3 layer” is the outage.
The awkward part is that nothing is technically broken. The endpoint is doing what it promised. Your system just never decided what it needed from RPC in the first place. So what are you really buying when you choose Infura, Alchemy, or a self-hosted node?
Setting your RPC requirements in writing before choosing a provider
A good comparison starts with your own contract. “Fast” and “reliable” are feelings. Your application needs specific guarantees around data freshness, historical access, and failure behavior. If you don’t define them, you’ll end up optimizing for the wrong thing and calling it a trade-off.
Define “correct data” for your product: Head state vs historical state
Many apps live at the head of the chain. They care about the latest block, pending state, and quick confirmations. Other apps care about history, and they care a lot. Portfolio timelines, compliance exports, on-chain analytics, and any feature that queries state at past block heights can lean on archival data.
Archive access is not a minor checkbox. Ethereum’s own documentation describes archive nodes as storing historical state that enables queries at any past block, and it also flags disk space as the biggest requirement, ranging into multiple terabytes depending on the client. When the requirement is “show balances as of block X,” you can’t paper over missing historical state with retries or caching. Your RPC plan has to support that read pattern by design.
Translate pricing models into engineering constraints
Infura and Alchemy both sell you access to Ethereum JSON-RPC, yet their pricing models encourage different engineering habits.
Infura’s pricing is expressed in daily credits and a throughput cap in credits per second on each plan. That makes budgeting intuitive, and it makes burst behavior very visible. A UI that sends fifty parallel reads can collide with the per-second cap even when total daily usage remains modest.
Alchemy measures usage through compute units, and it explicitly documents per-method compute unit costs. That pushes you to think in method mix. A “simple” request profile with expensive calls can cost more than a larger profile with cheap calls. This becomes relevant as soon as your app adds heavy log queries or trace-like workflows, because the expensive endpoints often dominate spend and throughput.
Decide your tolerance for latency spikes and rate limiting
Median latency rarely kills an app. Tail latency does. When block times are steady, a few slow RPC calls can still derail the UX because most frontends are built around timeouts and optimistic retries.
Rate limiting also behaves differently than many teams expect. A 429 response is not an exception in the moral sense. It’s a flow-control signal. Your RPC layer should treat throttling as a normal operating condition during bursts, and it should make backoff behavior consistent across the codebase. If you leave that logic scattered in UI and worker code, you’ll eventually ship a retry storm that turns a mild slowdown into a full incident.
Infura: Credit-based capacity planning and predictable defaults
Infura tends to appeal to teams that want boring infrastructure. Boring is good when you’re building product features and you want the connection layer to stay out of the way. The cost of boring is that you’ll feel constraints earlier when your data appetite grows.
Understand credit quotas and per-second throughput caps
Infura’s plans are defined using daily credits and a credits-per-second throughput limit. The important detail is that those are two separate ceilings. You can have plenty of daily headroom and still hit a per-second cap during a burst.
This tends to happen when a single user action triggers many reads at once. Token dashboards can do it. NFT galleries can do it. Admin tools can do it in the most dramatic way because they often query wide time ranges and large log sets. In that moment, “credits per second” stops being a number in a pricing table and starts being a system requirement.
A practical design move is to treat burst shaping as part of your product behavior. If a page loads too much data at once, no provider choice will make that a healthy design. Infura’s model simply makes the feedback immediate.
Match Infura to steady request patterns and common wallet flows
Infura can fit very well when your workload is stable, and your app is closer to a transaction gateway than a data platform. Teams building standard read flows, simple writes, and predictable background polling often prefer the clarity of credits. The system is easier to explain internally because “we spend credits” maps well to “we make calls.”
There’s also an ecosystem aspect. Infura sits in a familiar lane for many Ethereum developers, and that familiarity reduces friction when you’re integrating tooling that expects conventional JSON-RPC behavior. You still need to be deliberate about your own caching and batching. You just don’t have to learn a new economic model to predict what a call costs.
Identify early pressure points: Bursts, polling, and heavy log queries
Infura becomes less comfortable when your app shifts from “reads and writes” to “reads like an indexer.” Heavy log queries tend to be a turning point. Polling loops can be another. They look harmless in isolation, then multiply across users, tabs, and background workers.
The common failure pattern here is subtle. A new feature adds frequent reads. The reads are small, so nobody worries. Then a marketing campaign drives traffic, and the per-second cap shows up as a sudden error rate. Teams often respond by adding retries, which makes the burst bigger. If you see this pattern, it’s a sign to invest in request shaping and caching rather than arguing about endpoints.
Alchemy: Compute-unit economics and method-level performance tuning
Alchemy’s model rewards teams that want to reason about performance and cost at the method level. It can feel more “engineering-native,” especially when the application’s RPC profile is complex and changes over time.
Map your method mix to compute units and throughput ceilings
Alchemy defines compute units as a measure of resources consumed by API methods, and it publishes compute unit costs per method in its documentation. Throughput is framed as compute units per second, which means high-cost methods can effectively reduce your request rate under load even when the request count stays the same.
This is useful when you’re moving past guesswork. If a single endpoint dominates cost, it gives you a concrete reason to redesign a feature. If a log query is expensive, you can decide whether to cache it, narrow it, or push it to a dedicated indexing layer. You’re no longer arguing about “too many requests.” You’re arguing about which requests deserve to exist.
Engineer retries around 429 responses and backoff behavior
Alchemy documents throughput concepts and support material that encourage treating throttling as a managed condition. That matters because compute-based systems can hit throughput ceilings in ways that surprise teams that focus on request count. A UI can fire a small number of calls that are individually expensive and still trigger backpressure.
In practice, your retry strategy becomes part of your cost strategy. If you retry too aggressively, you spend more compute, and you extend the period of throttling. If you back off properly, you protect user experience and reduce wasted work. This is one reason a centralized RPC gateway is worth building even when you use a managed provider. It gives you one place to express backoff rules and keep them consistent.
Use spend controls and alerts as operational guardrails
Compute-unit billing can be forgiving when traffic grows gradually. It can also mask a regression until the bill tells you. A single release can change method mix, widen log ranges, or introduce a new polling loop. That can shift cost faster than user growth.
A mature setup treats usage controls as a production signal. Alchemy provides account-level usage concepts and guidance around how usage is measured. Your own alerting should translate that into action: identify which feature changed the profile, identify which method dominates, and roll back or mitigate quickly.
Self-hosted Ethereum nodes: Operational ownership, storage, and control
Self-hosting is appealing for reasons that have nothing to do with price. It’s about control, compliance posture, and the ability to shape your own node behavior. The trade is operational gravity. Once you self-host, you’re responsible for being correct at the infrastructure layer.
Run execution and consensus clients as a single service
After The Merge, running an Ethereum node means running an execution client and a consensus client together. Ethereum.org is explicit about this requirement. That alone changes the staffing equation for teams who assume “a node is a node.”
Operationally, you’re now managing coordination between two components. You monitor sync status. You manage upgrades with compatibility in mind. You validate that your node is serving what your application expects. If your app depends on “latest” data, you need monitors that catch a node falling behind before users do.
Plan disk, pruning, snapshots, and archive requirements
Disk is the budget line that keeps coming back. Geth’s hardware requirements documentation notes that disk is usually the primary bottleneck, gives a concrete view of full node storage, and states that a full archive node can require more than 12TB. Ethereum.org’s archive node page also frames archive disk requirements as multi-terabyte and stresses SSD use for syncing and head updates.
This is where “self-hosted” splits into two different commitments. A pruned full node can be manageable. An archive node can become a storage and maintenance project of its own. If you need archive-grade reads, you should decide whether you want to run archive in-house or pay someone else to carry that weight. The honest answer is often “we pay until the requirement becomes strategic.”
Choose self-hosting for compliance, data locality, and custom indexing
There are legitimate reasons to own your node even when managed providers are excellent. Data locality requirements can force it. Regulatory posture can encourage it. Some products also benefit from custom indexing or caching behavior that is simpler to build when you control the node environment.
Self-hosting can also be part of a multi-layer design. Some teams self-host for baseline reliability and use a managed provider as a burst buffer or geographic expansion layer. That design requires careful routing and monitoring, yet it can give you a more resilient system than a single-provider setup.
Build an RPC connection layer that supports failover and cost control
The best provider choice can still fail if your app treats RPC calls as a raw utility function. Your connection layer should behave more like a service. It should absorb spikes, normalize errors, and give you levers for cost control.
Add an RPC gateway for caching, retries, and circuit breakers
A gateway doesn’t have to be large. It can be a small service or module that sits between your app and the provider endpoints. The point is centralization. You want one place where retries are controlled, where timeouts are consistent, and where you can implement circuit breakers when an endpoint degrades.
This also makes failover practical. If every part of your system holds its own provider URL, failover becomes an emergency change. If your gateway owns routing, failover becomes a policy decision, and policy decisions are easier to test.
Reduce request fan-out with batching policies and cache strategy
Fan-out is the quiet killer of RPC budgets. A single screen can trigger dozens of reads, and those reads can multiply with tabs, refreshes, and background tasks. The cleanest fix is often product-level: load less at once, and defer what the user hasn’t asked to see.
Batching can help when it reduces overhead and makes the work more predictable. It can also increase blast radius when one bad call poisons a batch. Your gateway should decide where batching is safe and where individual retries are healthier. That decision should be based on measured behavior, not intuition.
Conclusion
Infura, Alchemy, and self-hosted nodes each solve the same surface problem and a different system problem underneath. Infura gives you a credit-based model with clear daily quotas and throughput caps that make burst behavior easy to reason about. Alchemy gives you compute-unit economics and method-level costs that encourage tuning based on what your app actually calls. Self-hosting gives you control and flexibility, while demanding that you own execution and consensus clients and the storage reality of full and archive modes.
The choice becomes calmer when you design the connection layer as infrastructure. Define what “correct” means for your product. Treat rate limiting as flow control. Centralize retries and caching. Once those decisions are real, provider selection stops being a late-night switch and starts being a deliberate architecture choice.




