Skip to main content
The Maestro Symphony is a fast, mempool-aware, and extensible Bitcoin indexer and API server. It provides a framework for indexing UTXOs, metaprotocols, and any other onchain activity. This guide explains how to construct and integrate custom logic to be extracted and persisted during transaction processing by the Maestro Symphony indexer.

Steps

1. Create a New Indexer Project and Initialize it

After forking the repo, create a file or module in the /custom subdirectory. Setup a new project directory
Bash
Create the files (plus any extra that you need)
Bash
Generate the mod.rs (and add your related files)
Bash
It is recommended to split logic across multiple files (see the runes indexer for reference).

2. Register a New Enum Variant

Create a new TransactionIndexerType enum variant:
Text
Add your variant only at the end. Example:
Rust
⚠️ Do not reorder or delete existing variants. They are encoded as u8 and reused in key encodings. Any change will corrupt existing indexed data unless starting from a clean state.

3. Define the Indexer Object

Implement a struct that represents your indexer and implements the ProcessTransaction trait.
Rust
Where:
  • task: read/write interface to storage
  • tx: the transaction being processed
  • ctx: context with input resolver, block height, hash, network, arbitrary data to outputs, etc.
A resolver lets you provide a transcation input UTXO reference and receive the corresponding transaction output UTXO. Reference:
runes/indexer.rs#L41-L61

4. Implement and Handle Config

Your indexer should expose a new() function that takes a configuration struct and returns an instance of the indexer. This enables configuration-driven behavior such as start_height, track_inputs, or custom logic.
Rust
The MyProjIndexerConfig struct should define fields relevant to your indexer. Reference

5. Define Storage Tables

Define custom key-value tables for storing the new data using the define_indexer_table! macro.
Text
Example:
Rust
Rust
Each table must:
  • Have a unique table ID
  • Use your new enum variant
  • Use key/value types that implement Encode and Decode
Reference:
tx_count_by_address.rs#L20-L26

6. Implement ProcessTransaction

Process each transaction by:
  • Iterating over inputs, ouputs, resolving UTXOs, etc.
  • Reading/writing to storage with
Rust
Example:
tx_count_by_address.rs#L38-L76

7. Register Module and Add to Factory

Add your my_proj module in custom/mod.rs:
Rust
Reference Next, add your variant to:
  • The TransactionIndexerFactory enum
  • The create_indexer function
Rust

8. (Optional) Attach Metadata to UTXOs

To persist data across transactions using UTXOs (e.g., inscriptions, runes), you can attach metadata during output processing:
Rust
Later, during input resolution:
Rust
Examples: This saves storage and avoids manually tracking UTXOs elsewhere.
For working examples, refer to:

🎉 You’re Done!

You have now walked through a guide on how to index a custom piece of data and add an API endpoint using the Maestro Symphony. Be sure to check out Maestro’s additional services for further assisting your development of building on Bitcoin.
SupportIf you are experiencing any trouble with the above, reach out on Discord.