Skip to main content

Balances & Holders Cubes

These cubes are query-only

Balances and Holders are derived views that answer "what is true now", so there is no underlying event to push. A subscription against either is a valid document and the socket stays open, but no message is ever delivered — on EVM or Tron.

For live balances, read the balance once and then keep it current from a stream that does fire: EVM.TransactionBalances or EVM.Transfers (and Tron.Transfers on Tron). See which cubes support subscriptions.

Two cubes answer balance questions, and picking the right one matters more than the fields you select:

CubeQuestion it answersShape
BalancesWhat does this address hold?Current balance per address, live — no snapshot date
HoldersWho holds this token?A token's holders ranked by balance, as a dated snapshot

Both read from aggregate-state tables (balances_by_address / balances_by_currency), so they return the current state directly instead of replaying every change.

Availability

Balances and Holders exist on EVM networks (EVM(network: …)) and Tron (Tron).

They do not exist on Solana. Solana balance changes are queried with Solana.BalanceUpdates and Solana.InstructionBalanceUpdates.

Balances — what an address holds​

Balances returns one row per address/currency pair with the current amount.

Balance fields: Address, Amount, AmountInUSD, UpdateCount, FirstChangeTime, LastChangeTime.

Its where filter accepts Balance.Address plus Currency and Block. Note there is no amount filter on Balances — see Holders if you need to filter or rank by balance size.

Token balance for one or more addresses​

query TokenBalances($addresses: [String!], $token: String!) {
EVM(network: eth, dataset: combined) {
Balances(
where: {
Balance: { Address: { in: $addresses } }
Currency: { SmartContract: { is: $token } }
}
orderBy: { descending: Balance_Amount }
) {
Balance {
Address
Amount
AmountInUSD
UpdateCount
LastChangeTime
}
Currency {
Symbol
Name
SmartContract
}
}
}
}
{
"addresses": [
"0x28C6c06298d514Db089934071355E5743bf21d60",
"0x21a31Ee1afC51d94C2eFcCAa2092aD1028285549"
],
"token": "0xdac17f958d2ee523a2206206994597c13d831ec7"
}

To exclude zero balances, apply the filter on the field rather than in where: Amount(selectWhere: { gt: "0" }).

Native balance​

Filter on Currency: { Native: true } to get the chain's native asset instead of a token:

{
EVM(network: eth, dataset: combined) {
Balances(
where: {
Balance: { Address: { is: "0x28C6c06298d514Db089934071355E5743bf21d60" } }
Currency: { Native: true }
}
) {
Balance {
Address
Amount
AmountInUSD
}
Currency {
Symbol
Native
}
}
}
}

The same query works on Tron by swapping the selector for Tron and using a Tron address.

Classifying an address from its balance metadata​

UpdateCount with LastChangeTime separates wallet types without any labelling data:

  • Very high UpdateCount, LastChangeTime seconds ago — exchange hot wallet or payment processor; the balance churns continuously.
  • Single-digit UpdateCount on a large balance — cold storage, treasury or custody. Funded once, rarely touched.
FirstChangeTime is not the address's first-ever activity

FirstChangeTime reflects the earliest change within the balances table's retention window, not the first time the address ever moved funds. For true first-activity, query Transfers with an ascending time order instead.

Holders — who holds a token​

Holders lists a token's holders, ranked. It takes a date argument for the snapshot day, and unlike Balances it does accept a balance filter — which is what makes large tokens tractable.

query TopHolders($token: String!, $floor: String!, $date: String!) {
EVM(network: eth) {
Holders(
limit: { count: 100 }
orderBy: { descending: Balance_Amount }
date: $date
where: {
Currency: { SmartContract: { is: $token } }
Balance: { Amount: { ge: $floor } }
}
) {
Holder {
Address
}
Balance {
Amount
}
Currency {
Symbol
Name
}
}
}
}
{
"token": "0x514910771AF9Ca656af840dff83E8264EcF986CA",
"floor": "1000000",
"date": "2026-07-29"
}
Set a balance floor on large tokens

An unbounded top-N ranking across every holder of a very large token times out server-side — this is a dataset-size limit, not a syntax error. Ethereum USDT times out even with a 50,000,000 floor; Tron USDT behaves the same way.

The fix is a Balance: { Amount: { ge: … } } floor high enough to shrink the working set. For a complete holder distribution rather than the top of it, use Bitquery Cloud exports or Kafka streams rather than a synchronous GraphQL query.

Choosing a dataset​

DatasetWhen to use
combinedLatest balances. Queries realtime and archive and merges the results.
archiveHistorical snapshots, and balances for addresses that have not been active recently.
realtimeRecent state only. Some aggregates are unavailable here — if you see "no table can query … consider use archive dataset", switch to combined or archive.

Daily balance history​

Balances in the archive dataset gives you one row per address per day, exposed as Block.Date. A 30-day balance history is one query returning 30 rows.

query DailyBalanceHistory {
EVM(network: eth, dataset: archive) {
Balances(
where: { Balance: { Address: { is: "0x28c6c06298d514db089934071355e5743bf21d60" } } }
orderBy: { descending: Block_Date }
limit: { count: 30 }
) {
Block {
Date
}
Balance {
Amount
AmountInUSD
}
Currency {
Symbol
}
}
}
}

Always order by Block_Date. Without it you get an arbitrary day and the query still succeeds, which makes the mistake silent.

You needUse
Current balance per addressBalances (latest row)
Balance on a past date, or a daily seriesBalances with Block.Date — or Holders(date: …), which agrees exactly
A token's holders, rankedHolders
When a position first or last movedBalances — FirstChangeTime, LastChangeTime, UpdateCount
The individual transfers behind a changeTransfers

The daily aggregate does not say why a balance moved. For that, use Transfers plus transaction context, or TransactionBalances for per-transaction balance changes.

Build with Bitquery

Ready to run this in production?

Get an API key and run these queries in minutes, or talk to us about plans and enterprise delivery.