Previous Module
Contract Upgrade Proxy

💼 Real-World Patterns: Uniswap & Aave

Discover how production dApps use The Graph

Query blockchain data efficiently with The Graph

🚀 Production Indexing Patterns

Real dApps need more than basic indexing. Aggregations track totals (daily volume, TVL). Time-series data enables charts (price history, growth). Relationships connect entities (user → positions → tokens). Subscriptions push live updates (new swaps, transfers). These patterns power Uniswap dashboards, Aave analytics, OpenSea collections, and every major DeFi protocol. Master them to build production-grade dApps.

🎮 Interactive: Pattern Explorer

Explore common indexing patterns used in production dApps. Select a pattern to see schema definition, mapping code, and real-world examples.

📊

Aggregation Entities

Track cumulative stats (totals, counts, averages) by creating aggregate entities updated on every event

💡 Use Cases

Token total supply, user transaction count, protocol TVL, daily volume

Code Implementation
// Schema
type DailyVolume @entity {
  id: ID! # Format: "YYYY-MM-DD"
  date: String!
  volumeUSD: BigDecimal!
  txCount: Int!
}

// Mapping
export function handleSwap(event: SwapEvent): void {
  let dayId = event.block.timestamp.toI32() / 86400
  let id = dayId.toString()
  
  let daily = DailyVolume.load(id)
  if (!daily) {
    daily = new DailyVolume(id)
    daily.date = new Date(dayId * 86400 * 1000).toISOString()
    daily.volumeUSD = BigDecimal.fromString("0")
    daily.txCount = 0
  }
  
  daily.volumeUSD = daily.volumeUSD.plus(event.params.amountUSD)
  daily.txCount = daily.txCount + 1
  daily.save()
}
🌐 Real-World Examples

Uniswap tracks daily volume, Aave tracks total deposited, compound tracks supply rates over time

🏗️ Architecture Best Practices

Separate Concerns: Create distinct entities for raw events (Transfer), aggregates (DailyVolume), and snapshots (TokenHourData). Don't mix.
Efficient IDs: Use composite keys (token-timestamp, user-token) for unique identification. Consistent format prevents duplicates.
Derived Fields: Use @derivedFrom for reverse lookups (User → Positions). Avoids manual array updates, keeps data consistent.
Immutable Events: Never update event entities (Transfer, Swap). Create new entities. Simplifies debugging and maintains history.

⚙️ Performance Optimization

Index Key Fields
Fields used in where/orderBy should be indexed. The Graph indexes IDs + custom fields automatically.
Batch Updates
Update aggregates in-memory, save once at end of handler. Reduces database writes.
Limit Nesting
Deep entity relationships (3+ levels) slow queries. Keep relationships shallow.
Prune Old Data
Archive historical data older than 1 year. Keeps subgraph lean and fast.

🎯 Production Checklist

Set startBlock: Skip blocks before contract deployed (saves hours of sync time).
Handle Edge Cases: Check for null/undefined before accessing nested data. Use entity.load() safely.
Monitor Sync Status: Track subgraph health, sync lag, and errors. Set alerts for indexing failures.
Version Control: Use semantic versioning for subgraph deployments. Keep changelog of schema changes.
Test Thoroughly: Run local Graph Node, test with historical data, verify queries before mainnet deploy.
← Query Optimization