Project Structure

graphite init creates the following layout:

my-subgraph/
├── Cargo.toml           # Rust crate (cdylib), declares graphite dependency
├── graphite.toml        # Graphite config: contracts, ABIs, output dir
├── subgraph.yaml        # The Graph manifest (generated by `graphite manifest`)
├── schema.graphql       # GraphQL entity schema (you write this)
├── abis/
│   └── MyContract.json  # ABI JSON (fetched or copied manually)
└── src/
    ├── lib.rs           # Your handlers (you write this)
    └── generated/       # Auto-generated by `graphite codegen` — do not edit
        ├── mod.rs
        ├── mycontract.rs   # Event and call structs from the ABI
        └── schema.rs        # Entity builders from schema.graphql

Key Files

Cargo.toml

A standard Rust crate configured as a cdylib (dynamic library), which is what the WASM target needs:

[lib]
crate-type = ["cdylib"]

[dependencies]
graphite = { package = "graphite-sdk", version = "1", default-features = false }
graphite-macros = "1"
graph-as-runtime = "1"

graphite.toml

The single source of truth for your subgraph configuration. graphite codegen and graphite manifest both read from it. See the graphite.toml reference for all options.

subgraph.yaml

Generated by graphite manifest. You should not edit it by hand — regenerate it whenever graphite.toml or schema.graphql changes. The manifest declares language: wasm/assemblyscript, which is how graph-node accepts Graphite WASM without modification.

src/generated/

Everything in here is overwritten every time you run graphite codegen. Never edit these files directly.

  • {contract_name}.rs — one struct per event and call, with typed fields matching the ABI. Each struct implements FromRawEvent for decoding.
  • schema.rs — one struct per @entity type in schema.graphql. Each struct has new, load, save, remove, and a setter for every field.

src/lib.rs

Where you write your handler functions. The crate must be no_std when targeting WASM:

#![allow(unused)]
#![cfg_attr(target_arch = "wasm32", no_std)]
fn main() {
extern crate alloc;
}

Tests live here too and run natively with cargo test.