home / skills / dojoengine / book / dojo-indexer

dojo-indexer skill

/skills/dojo-indexer

This skill helps you configure and use the Torii indexer for GraphQL queries, real-time subscriptions, and SQL access to your world state.

npx playbooks add skill dojoengine/book --skill dojo-indexer

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
6.3 KB
---
name: dojo-indexer
description: Set up and configure Torii indexer for GraphQL queries, gRPC subscriptions, and SQL access. Use when indexing your deployed world for client queries or real-time updates.
allowed-tools: Read, Write, Bash, Grep
---

# Dojo Indexer (Torii)

Set up and use Torii, the Dojo indexer, for efficient querying and real-time subscriptions to your world state.

## When to Use This Skill

- "Set up Torii indexer"
- "Configure GraphQL for my world"
- "Create subscriptions for entity updates"
- "Query world state efficiently"

## What This Skill Does

Manages Torii indexer:
- Start and configure Torii
- Create GraphQL queries
- Set up real-time subscriptions
- Access SQL database directly

## Quick Start

**Start Torii:**
```bash
torii --world <WORLD_ADDRESS>
```

This starts Torii with default settings:
- GraphQL API at `http://localhost:8080/graphql`
- gRPC API at `http://localhost:8080`
- In-memory database (for development)

**Production configuration:**
```bash
torii --world <WORLD_ADDRESS> --db-dir ./torii-db
```

## What is Torii?

Torii is the Dojo indexer that:
- Watches blockchain for world events
- Indexes model state changes
- Provides GraphQL API for queries
- Provides gRPC API for subscriptions
- Offers SQL access for complex queries

**Why use Torii:**
- Faster than direct RPC queries
- Complex queries (filters, pagination)
- Real-time subscriptions
- Type-safe GraphQL schema

## GraphQL API

Torii provides GraphQL endpoint at `http://localhost:8080/graphql`

Use the GraphiQL IDE in your browser to explore the schema and test queries.

### Schema Structure

Torii generates two types of queries:

**Generic Queries:**
- `entities` - Access all entities with filtering
- `models` - Retrieve model definitions
- `transactions` - Query indexed transactions

**Model-Specific Queries:**
- `{modelName}Models` - Custom queries for each model
- Example: `positionModels`, `movesModels`

### Basic Queries

**Get all entities of a model:**
```graphql
query {
    movesModels {
        edges {
            node {
                player
                remaining
                last_direction
            }
        }
    }
}
```

**Get model metadata:**
```graphql
query {
    models {
        edges {
            node {
                id
                name
                classHash
                contractAddress
            }
        }
        totalCount
    }
}
```

### Pagination

**Cursor-based pagination:**
```graphql
query {
    entities(first: 10) {
        edges {
            cursor
            node {
                id
            }
        }
        pageInfo {
            hasNextPage
            endCursor
        }
    }
}
```

**Get next page:**
```graphql
query {
    entities(first: 10, after: "cursor_value") {
        edges {
            cursor
            node { id }
        }
    }
}
```

**Offset/limit pagination:**
```graphql
query {
    entities(offset: 20, limit: 10) {
        edges {
            node { id }
        }
        totalCount
    }
}
```

## Real-time Subscriptions

Subscribe to world state changes via WebSocket.

### Entity Updates

```graphql
subscription {
    entityUpdated(id: "0x54f58...") {
        id
        updatedAt
        models {
            __typename
            ... on Position {
                vec {
                    x
                    y
                }
            }
            ... on Moves {
                remaining
            }
        }
    }
}
```

### Event Stream

Monitor all world events:

```graphql
subscription {
    eventEmitted {
        id
        keys
        data
        transactionHash
    }
}
```

### Model Registration

Listen for new model registrations:

```graphql
subscription {
    modelRegistered {
        id
        name
        namespace
    }
}
```

## SQL Access

Torii stores data in SQLite, accessible for complex queries.

**Connect to database:**
```bash
sqlite3 torii.db
```

**Example queries:**
```sql
-- Count entities
SELECT COUNT(*) FROM entities;

-- Custom aggregations
SELECT AVG(value) FROM model_data WHERE model_name = 'Health';
```

## Client Integration

### JavaScript/TypeScript

```typescript
import { createClient } from '@dojoengine/torii-client';

const client = await createClient({
    rpcUrl: "http://localhost:5050",
    toriiUrl: "http://localhost:8080",
    worldAddress: WORLD_ADDRESS,
});

// Query entities
const positions = await client.getEntities({
    model: "Position",
    limit: 10
});

// Subscribe to updates
await client.onEntityUpdated(
    [{ model: "Position", keys: [playerId] }],
    (entity) => console.log("Position updated:", entity)
);
```

### Apollo Client (GraphQL)

```typescript
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';

const client = new ApolloClient({
    uri: 'http://localhost:8080/graphql',
    cache: new InMemoryCache(),
});

const { data } = await client.query({
    query: gql`
        query GetMoves {
            movesModels {
                edges {
                    node {
                        player
                        remaining
                    }
                }
            }
        }
    `
});
```

## Configuration Options

| Option | Description | Default |
|--------|-------------|---------|
| `--world` | World contract address | Required |
| `--rpc` | RPC endpoint URL | `http://localhost:5050` |
| `--db-dir` | Database directory | In-memory |
| `--http.cors_origins` | CORS origins | `*` |

## Development Workflow

**Terminal 1: Start Katana**
```bash
katana --dev --dev.no-fee
```

**Terminal 2: Deploy world**
```bash
sozo build && sozo migrate
```

**Terminal 3: Start Torii**
```bash
torii --world <WORLD_ADDRESS> --http.cors_origins "*"
```

## Troubleshooting

### "Connection refused"
- Check Torii is running
- Verify port (default 8080)
- Check firewall rules

### "World not found"
- Verify world address is correct
- Check RPC URL is accessible
- Ensure world is deployed

### "Slow queries"
- Use model-specific queries instead of generic `entities`
- Use pagination
- Request only needed fields

## Next Steps

After Torii setup:
1. Integrate with client (`dojo-client` skill)
2. Create optimized queries
3. Set up subscriptions
4. Monitor performance

## Related Skills

- **dojo-deploy**: Deploy world first
- **dojo-client**: Use Torii in clients
- **dojo-world**: Configure what Torii indexes
- **dojo-migrate**: Restart Torii after migrations

Overview

This skill sets up and configures Torii, the Dojo indexer, to expose your world state via GraphQL, gRPC subscriptions, and direct SQL access. It helps you index a deployed world so clients can run efficient queries and receive real-time updates. Use it to speed up reads, implement subscriptions, and run complex analytics against indexed data.

How this skill works

Torii watches the blockchain for world events and indexes model state changes into a local SQLite store. It exposes a GraphQL HTTP endpoint for queries and a gRPC/WebSocket interface for real-time subscriptions. You can also connect directly to the SQLite database for advanced SQL queries and aggregations.

When to use it

  • You have a deployed world and need fast, filterable queries for client apps
  • You want real-time subscriptions for entity updates or event streams
  • You need type-safe, model-specific GraphQL queries for UI development
  • You require SQL access for reporting or complex aggregations
  • You need a local development indexer that mirrors world state

Best practices

  • Start Torii with --world and set --db-dir for production persistence
  • Prefer model-specific GraphQL queries over generic entities for performance
  • Use cursor-based pagination for stable pagination in UIs
  • Limit requested fields to only what the client needs
  • Restart Torii after world migrations to refresh indexed schemas

Example use cases

  • Run positionModels queries to fetch player positions with pagination
  • Subscribe to entityUpdated for a player entity to drive live UIs
  • Stream eventEmitted subscriptions to build an audit or analytics pipeline
  • Connect to torii.db with sqlite3 for custom aggregations and counts
  • Integrate Torii with Apollo Client to serve a real-time dashboard

FAQ

What ports and endpoints does Torii expose by default?

By default Torii serves GraphQL at http://localhost:8080/graphql and gRPC/WebSocket on port 8080; RPC defaults to http://localhost:5050.

How do I make Torii persistent for production?

Start Torii with --db-dir pointing to a directory (e.g., --db-dir ./torii-db) to persist SQLite files instead of using the in-memory DB.