Documentation Index
Fetch the complete documentation index at: https://docs.moralis.com/llms.txt
Use this file to discover all available pages before exploring further.
Question it answers
“Give me every NFT transfer — by contract 0x…, by wallet 0x…, or for a single (contract, token_id).”
A single recipe serves all three access paths. It mirrors the on-chain subset of Moralis GET /nft/{address}/transfers (by contract), GET /{address}/nft/transfers (by wallet), and GET /nft/{address}/{token_id}/transfers (single token). It carries no off-chain enrichment — the source array has no collection metadata or address labels (see Fidelity gaps).
What you get
One row per NFT transfer, mapped straight from Moralis-indexed, normalized per-block onchain data:| Column | Description |
|---|---|
token_address | The NFT contract that emitted the transfer |
token_id | The token id — a uint256 big decimal stored as text (never numeric); compare as strings |
from_address, to_address | The two sides of the transfer |
amount | The ERC-1155 quantity (1 for ERC-721) |
contract_type | ERC721 or ERC1155 (the emitted tokenType) |
initiated_by | The address that initiated the transfer |
tx_hash | Transaction that produced the transfer |
block_number, transaction_index, log_index | On-chain ordering tuple |
block_timestamp | Block time |
Source
The transform reads one per-block array and lands one row per transfer:nftTokenTransfers
Fields map straight from the source struct — tokenAddress, tokenId (as a string), fromAddress, toAddress, amount, tokenType (→ contract_type), and initiatedBy. There’s no price or metadata join — this is a flat event stream.
Destination
| Destination | Table | Read pattern |
|---|---|---|
| ClickHouse (first-class) | fact_nft_transfers | Prefix scan on (chain_id, token_address, token_id, block_number); by-wallet via bloom_filter skip indexes; read with FINAL or sum(sign) |
| Postgres | nft_transfers | Index on (token_address, block_number DESC), (token_address, token_id, block_number DESC), and (from_address, …) / (to_address, …) |
| MySQL | nft_transfers | Same composite indexes (ascending) |
+1/−1 reorg pair for a row shares an identical key and collapses cleanly. The fact table’s sort key is contract-first, so by-contract is a prefix scan on token_address and by-token-id a prefix scan on (token_address, token_id). By-wallet reads are served by bloom_filter data-skipping indexes on from_address and to_address.
Full schema
Below is the complete read table this recipe produces. Keep the columns you need and drop the rest (see Schema & flexibility).token_id and amount are stored at full uint256 width — token_id as text (hash-derived ENS / ERC-1155 ids routinely exceed any SQL numeric precision), amount as a wide decimal.
ClickHouse — fact_nft_transfers
ClickHouse — fact_nft_transfers
sign column drives reorg collapsing — read with FINAL or sum(sign), never a bare WHERE sign = 1. A single-node setup can use CollapsingMergeTree(sign) without the replication path.Postgres — nft_transfers
Postgres — nft_transfers
VARCHAR(80) for token_id and equivalent ascending composite keys. position is the block-level cursor used during backfill.Example reads
All transfers of an NFT contract, newest first (ClickHouse):Modes
Shipped defaults: ClickHousehybrid (backfill → realtime), Postgres / MySQL historical (one-shot backfill). For live/reorg-safe ingestion, use ClickHouse — see the overview.
The realtime reorg path needs a single-column
UNIQUE on the position column, but position is block-level (many transfers share one block), so array-expanded transfer rows can only carry a composite unique. Run realtime / hybrid on ClickHouse — its log table corrects reorgs per-block via the collapsing companion table. The Postgres / MySQL shapes here are intended for historical backfill.Multichain
The recipe is chain-parametrized — point it at any supported EVM chain or Solana. On Solana the samelogIndex can be assigned to multiple events in one instruction, so the event identity is widened with (from_address, to_address, token_address, token_id, amount) to keep rows distinct; the transfer log it produces is identical in shape.
Fidelity gaps
The recipe lands only what thenftTokenTransfers array carries. Fields a Moralis NFT transfers endpoint surfaces that have no onchain source in this array are omitted:
- Collection metadata (
token_name,token_symbol) — these come from the NFT contract / a metadata indexer, not the transfer event. Out of scope for a flat transfer log; see NFT Collection Metadata for the contract-metadata pattern. - Address labels / entity tags (
from_address_label,to_address_entity, …) — off-chain labels from a separate labelling service, not on-chain data. value— the native value attached to the transfer transaction isn’t carried on the transfer event; omitted.amount(the ERC-1155 quantity) is present.- Pre/post NFT balances — the recipe omits the balance surface to stay a flat event stream.
Related
NFT Trades
Marketplace sales with price — the trade-priced complement to raw transfers.
NFT Marketplace
The use case these NFT recipes power.

