---
title: Querying Indexed Data
description: Query indexed Thru stream tables directly with Drizzle.
source_url:
  html: https://thru.org/docs/indexing/querying-indexed-data/
  md: https://thru.org/docs/indexing/querying-indexed-data.md
---

# Querying Indexed Data

Use this page when the indexer is already writing rows and you want to consume them from your app or internal tooling.

## Direct Table Queries

Export the stream tables from your schema package, then query them with Drizzle like any other app table.

```ts
import { desc, eq } from "drizzle-orm";
import { db } from "./db";
import { tokenAccountsTable, tokenTransferEvents } from "./schema";

const recentTransfers = await db
  .select()
  .from(tokenTransferEvents)
  .where(eq(tokenTransferEvents.dest, "ta..."))
  .orderBy(desc(tokenTransferEvents.slot))
  .limit(20);

const ownerBalances = await db
  .select()
  .from(tokenAccountsTable)
  .where(eq(tokenAccountsTable.owner, "ta..."));
```

## When To Query Tables Directly

Direct queries are a good fit when:

- the backend route is internal to your app
- the query needs joins across multiple indexed tables
- you need auth, aggregation, or business-specific response shapes
- the result shape should evolve with your product rather than with stream definitions

## Practical Recommendation

For most apps:

1. query tables directly inside the backend for core product endpoints
2. wrap common queries in small repository functions
3. keep auth, aggregation, and response shaping in application code

## Related Pages

- [Indexing Overview](https://thru.org/docs/indexing/overview.md)
- [Build an Indexer](https://thru.org/docs/indexing/build-an-indexer.md)
- [Streams](https://thru.org/docs/indexing/streams.md)
- [Running the Indexer](https://thru.org/docs/indexing/running-the-indexer.md)
- [`@thru/indexer`](https://thru.org/docs/sdks/web-packages/indexer.md)
- [`@thru/replay`](https://thru.org/docs/sdks/web-packages/replay.md)
- [Web SDKs Overview](https://thru.org/docs/sdks/web.md)
