Overview
ASOF JOIN in DuneSQL lets you join two relations based on the closest matching row according to an inequality in theON
clause - typically on a timestamp or sequence field.
This is most useful when you need to:
- Get the latest price as of trade time
- Forward-fill sparse balance or config/state tables
- Enrich dense time grids (e.g. hourly/daily) from sparse event data
- Tracking actions of an ENS across addresses over time.
- Tracking actions of EIP-7702 enabled wallets by the contract they authorized to.
ASOF JOIN executes entirely at query time — it does not pre-materialize or store any helper tables. It is a runtime join optimized in the DuneSQL engine.
Syntax
Rules
- Exactly one inequality is required, comparing a right-side expression to a left-side expression using
<
,<=
,>
, or>=
. - Any number of equality predicates (left.sym = right.sym) are allowed and encouraged.
- ASOF JOIN returns only matched left rows (like INNER JOIN).
- ASOF LEFT JOIN returns all left rows and fills NULL when no neighbor exists.
Typically, expressions compare timestamps: e.g.
prices.ts <= trades.ts
will pick the latest price at or before the trade.Example
Dune’s ETH balances over time
See query on dune.com.Latest price at trade time
See query on dune.com.Forward-fill with ASOF LEFT JOIN
See query on dune.com.Performance
ASOF JOIN consistently outperforms LEAD() + range joins for large temporal enrichments. Below is a rounded summary from production-scale testing (millions of rows):ASOF JOIN combines cleaner SQL and runtime performance gains when data is sparse or when “nearest match” logic is required.
When to use ASOF JOIN
✅ Recommended when:- You need a point-in-time snapshot (latest state, price, config)
- You are forward-filling sparse events into a regular time spine
- Data is sparse or high-cardinality (wallet balances, token prices)
- You just need window aggregates (e.g. moving averages) → use window functions
- You already materialize reusable helper tables with valid ranges → consider pre-filled models
Limitations
- Exactly one inequality is required in the ON clause.
- Joins based on multiple inequalities are not supported — add extra conditions via equality or
WHERE
.
Best Practices
- Always constrain with equality first (token, address, etc.) to avoid scanning irrelevant rows.
- Use
ASOF LEFT
when you need to preserve all left rows, even if no match exists. - Prefer
<=
or>=
for clear open/closed interval intent. - Document the direction, as inequality can compare from right to left or from left to right (e.g.,
right.ts <= left.ts
orleft.ts >= right.ts
):<=
→ “most recent up to this timestamp” (historical lookup)>=
→ “next upcoming record” (future-effective lookup)
Think in terms of “as of X, what was true?” — that’s the strongest signal that ASOF JOIN is appropriate.