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:
bash1torii --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):
bash1torii --world <WORLD_ADDRESS> --indexing.controllers
Production configuration:
bash1torii --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 filteringmodels- Retrieve model definitionstransactions- Query indexed transactions
Model-Specific Queries:
{modelName}Models- Custom queries for each model- Example:
positionModels,movesModels
Basic Queries
Get all entities of a model:
graphql1query { 2 movesModels { 3 edges { 4 node { 5 player 6 remaining 7 last_direction 8 } 9 } 10 } 11}
Get model metadata:
graphql1query { 2 models { 3 edges { 4 node { 5 id 6 name 7 classHash 8 contractAddress 9 } 10 } 11 totalCount 12 } 13}
Pagination
Cursor-based pagination:
graphql1query { 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:
graphql1query { 2 entities(first: 10, after: "cursor_value") { 3 edges { 4 cursor 5 node { id } 6 } 7 } 8}
Offset/limit pagination:
graphql1query { 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
graphql1subscription { 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:
graphql1subscription { 2 eventEmitted { 3 id 4 keys 5 data 6 transactionHash 7 } 8}
Model Registration
Listen for new model registrations:
graphql1subscription { 2 modelRegistered { 3 id 4 name 5 namespace 6 } 7}
SQL Access
Torii stores data in SQLite, accessible for complex queries.
Connect to database:
bash1sqlite3 torii.db
Example queries:
sql1-- Count entities 2SELECT COUNT(*) FROM entities; 3 4-- Custom aggregations 5SELECT AVG(value) FROM model_data WHERE model_name = 'Health';
Client Integration
JavaScript/TypeScript
typescript1import { 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)
typescript1import { 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
toml1# 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
bash1slot auth login 2 3slot deployments create <PROJECT_NAME> torii --config torii.toml --version <DOJO_VERSION>
Manage
bash1# 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
bash1katana --dev --dev.no-fee
Terminal 2: Deploy world
bash1sozo build && sozo migrate
Terminal 3: Start Torii
bash1torii --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-clientskill) - Create optimized queries
- Set up subscriptions
- 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