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
1torii --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)
With Controller indexing (recommended):
bash
1torii --world <WORLD_ADDRESS> --indexing.controllers
Production configuration:
bash
1torii --world <WORLD_ADDRESS> --db-dir ./torii-db --indexing.controllers
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
1query {
2 movesModels {
3 edges {
4 node {
5 player
6 remaining
7 last_direction
8 }
9 }
10 }
11}
Get model metadata:
graphql
1query {
2 models {
3 edges {
4 node {
5 id
6 name
7 classHash
8 contractAddress
9 }
10 }
11 totalCount
12 }
13}
Cursor-based pagination:
graphql
1query {
2 entities(first: 10) {
3 edges {
4 cursor
5 node {
6 id
7 }
8 }
9 pageInfo {
10 hasNextPage
11 endCursor
12 }
13 }
14}
Get next page:
graphql
1query {
2 entities(first: 10, after: "cursor_value") {
3 edges {
4 cursor
5 node { id }
6 }
7 }
8}
Offset/limit pagination:
graphql
1query {
2 entities(offset: 20, limit: 10) {
3 edges {
4 node { id }
5 }
6 totalCount
7 }
8}
Real-time Subscriptions
Subscribe to world state changes via WebSocket.
Entity Updates
graphql
1subscription {
2 entityUpdated(id: "0x54f58...") {
3 id
4 updatedAt
5 models {
6 __typename
7 ... on Position {
8 vec {
9 x
10 y
11 }
12 }
13 ... on Moves {
14 remaining
15 }
16 }
17 }
18}
Event Stream
Monitor all world events:
graphql
1subscription {
2 eventEmitted {
3 id
4 keys
5 data
6 transactionHash
7 }
8}
Model Registration
Listen for new model registrations:
graphql
1subscription {
2 modelRegistered {
3 id
4 name
5 namespace
6 }
7}
SQL Access
Torii stores data in SQLite, accessible for complex queries.
Connect to database:
Example queries:
sql
1-- Count entities
2SELECT COUNT(*) FROM entities;
3
4-- Custom aggregations
5SELECT AVG(value) FROM model_data WHERE model_name = 'Health';
Client Integration
JavaScript/TypeScript
typescript
1import { createClient } from '@dojoengine/torii-client';
2
3const client = await createClient({
4 rpcUrl: "http://localhost:5050",
5 toriiUrl: "http://localhost:8080",
6 worldAddress: WORLD_ADDRESS,
7});
8
9// Query entities
10const positions = await client.getEntities({
11 model: "Position",
12 limit: 10
13});
14
15// Subscribe to updates
16await client.onEntityUpdated(
17 [{ model: "Position", keys: [playerId] }],
18 (entity) => console.log("Position updated:", entity)
19);
Apollo Client (GraphQL)
typescript
1import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
2
3const client = new ApolloClient({
4 uri: 'http://localhost:8080/graphql',
5 cache: new InMemoryCache(),
6});
7
8const { data } = await client.query({
9 query: gql`
10 query GetMoves {
11 movesModels {
12 edges {
13 node {
14 player
15 remaining
16 }
17 }
18 }
19 }
20 `
21});
Configuration Options
| Option | Description | Default |
|---|
--world | World contract address | Optional (since Torii 1.6.0) |
--rpc | RPC endpoint URL | http://localhost:5050 |
--db-dir | Database directory | In-memory |
--config | Path to TOML configuration file | None |
--http.cors_origins | CORS origins | * |
Slot Deployment (Remote)
Slot provides hosted Torii instances. Slot requires a TOML configuration file.
Create Configuration
toml
1# torii.toml
2world_address = "<WORLD_ADDRESS>"
3rpc = "<RPC_URL>"
4
5[indexing]
6controllers = true
See the Torii configuration guide for all TOML options (indexing, polling, namespaces, etc.).
Deploy
bash
1slot auth login
2
3slot deployments create <PROJECT_NAME> torii --config torii.toml --version <DOJO_VERSION>
Manage
bash
1# Stream logs
2slot deployments logs <PROJECT_NAME> torii -f
3
4# Delete and recreate (safe — all data is on-chain)
5slot deployments delete <PROJECT_NAME> torii
Development Workflow
Terminal 1: Start Katana
bash
1katana --dev --dev.no-fee
Terminal 2: Deploy world
bash
1sozo build && sozo migrate
Terminal 3: Start Torii
bash
1torii --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:
- Integrate with client (
dojo-client skill)
- Create optimized queries
- Set up subscriptions
- Monitor performance
- dojo-deploy: Deploy world first
- dojo-client: Use Torii in clients
- dojo-world: Configure what Torii indexes
- dojo-migrate: Restart Torii after migrations