- Category
- Operations
- Reading time
- 11 minutes
- Published
latest vs safe vs finalized: choosing an EVM RPC block tag
Many EVM RPC methods accept a block parameter, and latest is the convenient default. That convenience can hide several different decisions: how fresh the result must be, whether a short reorganization is acceptable, whether several reads must describe one state, and whether another endpoint interprets the same tag consistently.
safe and finalized offer stronger stability on Ethereum, but they are not universal synonyms for a fixed confirmation count across every EVM network. A block number identifies a height but can later refer to a different canonical block. pending can describe a node-local candidate state that another endpoint never observed.
This guide turns those choices into an operational policy. It explains what each tag means, when to resolve a tag to a block hash, how an indexer can combine fast provisional data with durable checkpoints, and how to test the behavior before relying on it in production.
What is the short answer?
Use latest for a deliberately fresh view whose result may change or be reorganized. Use safe when the application can trade some freshness for a block that is unlikely to be reorganized under the network's stated assumptions. Use finalized when the workflow needs the strongest finality signal exposed by the network and can accept a larger delay. Use pending only for questions about a node's local candidate state.
For a logical operation with several related reads, first resolve the chosen tag to a block number and hash. Then pin compatible calls to that exact block, preferably by hash where the method and endpoint support it. A tag selects a moving boundary; it does not by itself guarantee that five calls made at different times all read the same state.
Do not transfer Ethereum's semantics to another EVM chain without testing. Support for safe, finalized, pending, block-hash parameters, and canonicality checks varies by network, client, method, and endpoint. A production policy needs a capability test and an explicit fallback behavior, not just a preferred tag.
What does each EVM block tag mean?
The current Ethereum Execution API definition distinguishes five named block references. Their differences are about availability, stability, and whose view is being described.
| Reference | What it selects | Typical use | Main risk |
|---|---|---|---|
| latest | The newest canonical block observed by the client | Fresh dashboards, head monitoring, provisional reads | The block can be reorganized, and endpoints can observe different heads |
| safe | The newest block considered safe under the network's consensus assumptions | Low-latency reads that need more stability than latest | Support and exact semantics are network-specific |
| finalized | The newest block carrying the network's strongest exposed finality status | Durable checkpoints, stable caches, settlement-sensitive reads | It is less fresh, can stop advancing during a finality delay, and is not identical across chains |
| pending | A sample next block or pending state assembled by the client | Nonce, balance, or simulation questions that intentionally include local pending transactions | Mempools and candidate blocks differ between nodes, so results are endpoint-local |
| earliest | The lowest block the client makes available | Boundary discovery and historical probes | It should not be assumed to mean genesis on every endpoint |
| block number | The block at a particular height in the endpoint's current view | Backfills and repeatable ranges | A reorganization can replace the hash at that height |
| block hash | One specific block identity | Coherent multi-call reads and reorg-aware verification | Not every method accepts a hash, and the block may later be non-canonical or unavailable |
How do safe and finalized differ on Ethereum?
On Ethereum, latest follows the execution block at the node's current head. Normal network conditions can still replace a recent head block. The safe tag points to a block that consensus considers safe from reorganization under an honest-majority and network-synchrony model. The finalized tag points to the most recent crypto-economically finalized block.
Ethereum finality is based on validator votes for checkpoints. The official proof-of-stake documentation explains that a checkpoint becomes justified and an earlier justified checkpoint becomes finalized after the required supermajority links. Reverting finalized history would therefore require a critical consensus failure and major economic penalties, not an ordinary short fork.
That stronger guarantee is why finalized is useful for irreversible application actions and stable caches. It is not a promise that the tag advances at a fixed wall-clock interval. If the network stops finalizing, the correct finalized block can remain unchanged while latest continues moving. Monitor both the returned block identity and the age or distance of the boundary your application depends on.
Why does a block tag not create a consistent snapshot?
Suppose a service reads two account balances and then calls a contract, passing latest to every request. A new block can arrive between those calls. Each response can be correct on its own while the combined view never existed at one block. The same problem can occur with safe or finalized when the boundary advances during a longer workflow.
Resolve the tag once with eth_getBlockByNumber, store the returned number, hash, and parent hash, then run the remaining reads against that selected block. Use the same identity for database rows, cache keys, logs, receipts, and traces. If one required method cannot address the chosen block or the endpoint no longer serves it, stop or retry the logical operation instead of silently switching back to a moving tag.
This is especially important for JSON-RPC batches. A batch reduces transport overhead, but the protocol does not require every item to execute against one snapshot. The batching guide covers response matching and partial failures; block pinning is the separate step that keeps related state reads coherent.
When should you use a block number or block hash?
A block number is convenient for ranges and cursors, but it identifies a position rather than an immutable block. Store its hash as well. If block N is reorganized, the canonical block at N can keep the same number and have a different hash, transactions, receipts, logs, and state root.
For state methods that support it, EIP-1898 defines an object-form block parameter containing blockHash and an optional requireCanonical flag. It applies to methods including eth_getBalance, eth_getStorageAt, eth_getTransactionCount, eth_getCode, eth_call, and eth_getProof. With requireCanonical: true, an endpoint can report that a known block is no longer canonical rather than returning data without that distinction.
Method support still needs testing. Some calls accept a tag or number but not an EIP-1898 object. Others have their own hash parameter: for example, an eth_getLogs filter can target one blockHash. Build a method-by-method matrix for the exact workflow, and define how the application detects a mismatched or non-canonical result.
Which block reference fits each workload?
Choose from the consequence of stale or reversible data. A consumer-facing activity feed can show latest data as provisional and correct it after a reorganization. A balance used only for display can prefer freshness, while a payout decision may require a finalized block plus application-level verification. A simulation can use latest for immediate relevance or a stored hash for reproducibility.
For caches, separate mutable head data from immutable historical entries. Cache a latest result briefly and include its block identity when possible. A result tied to a verified finalized block can usually receive a longer policy because the application no longer expects an ordinary reorganization to replace it. Invalidate by block hash, not only by height.
For transaction UX, distinguish inclusion from finality. A receipt at latest says that an observed canonical block currently contains the transaction; it does not mean the transaction is finalized. Present confirmation state explicitly, and keep tracking the transaction's block hash until it reaches the application's chosen boundary.
How should an EVM indexer combine freshness and finality?
An indexer does not have to choose between waiting for finality and being current. It can maintain two boundaries: a provisional head for low-latency results and a durable checkpoint for data that crossed the chosen safety threshold. Store every provisional row with its block number and hash so it can be removed or replaced.
Before committing block N, verify that its parentHash matches the stored hash for N - 1. If the relationship breaks, find the common ancestor, roll back orphaned rows, and replay the canonical branch. Advance the durable cursor only after all expected data for the block is validated and committed atomically with the cursor. The log backfill guide and receipt indexing guide cover those completeness checks in detail.
A finalized tag can simplify the durable boundary on a network that implements it with semantics suitable for the product. It does not remove the need to store hashes or handle reorganization in the provisional region. If the tag is unsupported or stops advancing, the indexer should alert and pause the affected promotion step rather than silently substituting a guessed confirmation count.
What changes when requests can use more than one endpoint?
Two healthy endpoints can return different latest blocks because they observed the chain at different moments. Their pending views can differ even more because pending transactions are local. A reliable multi-endpoint workflow must therefore preserve the selected block identity across retries and failover.
Resolve the intended boundary, keep its hash fixed, and retry the same logical read against that block. Do not turn a timeout at block A into a successful answer from block B without making that change explicit to the application. When comparing endpoints, verify chain ID, block number, block hash, parent hash, and the method's result schema.
Test safe and finalized separately from latest. An endpoint that serves the head may reject a tag, return null, lag at that boundary, or implement a different network-specific model. The RPC failover guide explains the broader freshness and capability checks; the block-tag policy here supplies the consistency requirement that failover must preserve.
How do you test block-tag support before production?
Run the same probe against every EVM network and endpoint the application will use. Start with eth_chainId, then request eth_getBlockByNumber for latest, safe, finalized, and pending. Record whether each returns a block, null, or a JSON-RPC error, and store the number, hash, parent hash, timestamp, and observation time.
Next, exercise the real methods: state reads, eth_call, blocks, receipts, logs, proofs, or traces. Check which accept named tags, numbers, raw hashes, or EIP-1898 objects. Verify how an unavailable, pruned, unknown, or non-canonical block is represented. Repeat the probe after a new block, during a controlled endpoint switch, and after client or network upgrades.
Define pass criteria before testing. They should include the maximum acceptable distance between latest and the chosen stable boundary, how long that boundary may stop advancing, what constitutes an unsupported tag, and whether the workflow pauses or degrades to a documented alternative. Never convert an error into latest automatically for a settlement-sensitive or durability-sensitive operation.
EVM block-tag production checklist
- Classify each workflow by freshness, reorganization tolerance, and consequence of acting on reversible data.
- Treat
latest,safe,finalized, andpendingas different inputs, not interchangeable aliases. - Test every required tag on the exact network, method, and endpoint.
- Resolve a moving tag once before a multi-call operation.
- Store block number, hash, parent hash, and observation time together.
- Use a block hash and
requireCanonicalwhere the method supports EIP-1898. - Keep the selected block fixed across retries and endpoint changes.
- Separate provisional indexed data from the durable checkpoint.
- Roll back by block hash when parent continuity breaks.
- Pause or alert when a required stable boundary stops advancing.
- Cache head data and finalized historical data under different policies.
- Re-run the capability matrix after network, client, library, or endpoint changes.
The practical rule is simple: use a tag to choose a boundary, then use a block identity to keep the operation coherent.
Frequently asked questions
- Is finalized always the best EVM RPC block tag?
No. Finalized is appropriate when stability matters more than freshness and the network exposes a suitable finality signal. User interfaces, monitoring, and provisional indexing often need latest data, while pending is useful only for intentionally node-local pending-state questions.
- Can an EVM chain reject safe or finalized?
Yes. EVM compatibility does not guarantee identical consensus semantics or block-tag support. Test each tag and required RPC method on the exact network and endpoint, and define an explicit response to unsupported or stalled boundaries.
- Does latest return the same block from every RPC endpoint?
Not necessarily. Endpoints can observe the chain at different moments or temporarily disagree about the head. Compare block hashes as well as heights, and pin related reads to one selected block identity.
- Is a block number enough to protect against a reorganization?
No. A reorganization can replace the canonical block at the same height. Store the block hash and parent hash, validate continuity, and use hash-addressed reads where supported.
- Should an indexer wait for finalized blocks?
It depends on the product's latency and rollback requirements. Many indexers process recent blocks provisionally, retain block identity for rollback, and promote data to a durable checkpoint only after the chosen safety or finality boundary passes it.