Skip to main content
@thru/indexer is the public root entrypoint for building Thru indexers. The package exposes a single published entrypoint at the package root; there are no public subpath exports.

Install

npm install @thru/indexer @thru/replay drizzle-orm
You will also need a database driver and a Drizzle database/schema setup in the application that runs the indexer.

When to use it

Use @thru/indexer when you want to:
  • Define event streams for historical chain data.
  • Define account streams for mutable on-chain state.
  • Build Drizzle tables and Zod schemas from one schema definition.
  • Persist checkpoints so an indexer can resume after a restart.
  • Mount filtered, paginated REST routes over indexed data.
  • Run a background indexer that processes event and account streams together.
Choose @thru/indexer when you need to persist chain data, checkpoint progress, or expose read routes over the indexed data. Choose a different package when:
  • You only need an ordered feed and do not want to store the results yourself: use @thru/replay
  • You only need low-level encoding helpers for indexed data: use @thru/helpers

Main entrypoints

AreaExportWhat it does
Schema buildert, columnBuilder, buildDrizzleTableDefine typed Drizzle columns and build tables from a stream schema.
Stream definitionsdefineEventStream, defineAccountStreamCompile event and account stream definitions into runnable stream objects.
CheckpointscheckpointTable, getCheckpoint, updateCheckpoint, deleteCheckpoint, getAllCheckpoints, getSchemaExportsStore progress and export the tables needed for migrations.
API generationmountStreamRoutes, generateSchemas, paginationQuerySchema, paginate, parseCursorGenerate OpenAPI-backed list/get routes with pagination and filters.
RuntimeIndexerRun configured event and account streams against a database and chain client factory.
Shared typesApiConfig, StreamBatch, HookContext, IndexerConfig, IndexerResultType the stream hooks, API options, runtime config, and results.

Starting points

For most projects, the flow looks like this:
  1. Define one or more streams with defineEventStream or defineAccountStream.
  2. Export the stream tables, plus checkpointTable, from your Drizzle schema.
  3. Use Indexer to run the streams in the background, or mountStreamRoutes to expose them through Hono.

Typical workflow

import {
  Indexer,
  checkpointTable,
  defineAccountStream,
  defineEventStream,
  mountStreamRoutes,
  t,
} from "@thru/indexer";
import { ChainClient } from "@thru/replay";

const indexer = new Indexer({
  db, /* your Drizzle database */
  clientFactory: () => new ChainClient({ baseUrl: process.env.CHAIN_RPC_URL! }),
  eventStreams: [transfers],
  accountStreams: [tokenAccounts],
});

await indexer.start();
defineEventStream is for append-only chain events. defineAccountStream is for current account state that gets updated as chain data changes. Both return compiled stream objects with a Drizzle table on .table, which makes it easy to keep your schema and runtime in sync. mountStreamRoutes and generateSchemas are the public API layer. They build list and get endpoints with pagination, filtering, and JSON-safe serialization of values such as bigint and Date. Indexer is the runtime layer. Its config requires a database client and a clientFactory, and it supports event streams, account streams, a default start slot, safety margin, page size, and optional runtime validation.