Stacks Subgraphs Beta
Subgraphs are your own indexer, minus the node. Pick the events your app needs, write handlers, and get typed Postgres tables shaped exactly for your product — queryable over a REST API, the SDK, or a generated typed client.
It's the L3 surface: where raw events become the data your app actually wants. Install with bun add @secondlayer/subgraphs.
Ensure setup once, skipping any step already done:
- Skill: `bunx skills add ryanwaits/secondlayer --skill secondlayer -y`
- CLI: `bun add -g @secondlayer/cli`
- Auth: `sl login` then `sl whoami`
- Instance: `sl instance info`; if missing, start a trial from Billing or run `sl instance create --plan launch`
Subgraphs are declarative SQL tables that auto-index Stacks blockchain activity into queryable Postgres tables. Define named sources, a typed schema, and handlers in TypeScript, then deploy and query.
/secondlayer Help me create a subgraph from a Stacks contract. Ask me for the contract id and the events or function calls I care about. Scaffold with `sl subgraphs scaffold` so the module package and dependencies are prepared, explain the generated named sources and tables, let me review or customize the handlers, deploy with `sl subgraphs deploy`, query recent rows, then ask whether I want a subscription webhook.How it works
your shape, not a fixed one
The runtime feeds matched events into your handlers per block; the handlers write rows into your own schema. No node, no backfill scripts — redeploy and it reindexes for you.
Define a subgraph
A subgraph has three parts: sources (what events to listen for), a schema (what tables to create), and handlers (how to turn each event into rows). Writes are batched and flushed atomically per block.
import { defineSubgraph } from "@secondlayer/subgraphs";
export default defineSubgraph({
name: "stx-transfers",
sources: {
transfer: { type: "stx_transfer" },
},
schema: {
transfers: {
columns: {
sender: { type: "principal", indexed: true },
recipient: { type: "principal", indexed: true },
amount: { type: "uint" },
memo: { type: "text", nullable: true },
},
},
},
handlers: {
transfer: (event, ctx) => {
ctx.insert("transfers", {
sender: event.sender,
recipient: event.recipient,
amount: event.amount,
memo: event.memo,
});
},
},
});Each subgraph gets its own Postgres schema with system columns added automatically (_id, _block_height, _tx_id, _created_at). The full column-type list, the handler context API (upsert, findOne, aggregates), and monitoring patterns are in the docs.
Deploy & query
Scaffold from a contract's ABI, deploy, and query — via the CLI, the SDK, or the generated typed client:
# Scaffold from a deployed contract's ABI
sl subgraphs scaffold SP1234ABCD.token-transfers --output subgraphs/token-transfers.ts
# Deploy (or 'dev' to watch + auto-redeploy)
sl subgraphs deploy subgraphs/token-transfers.ts
# Generate a typed client (autocompletion + table types)
sl subgraphs generate token-transfers --output src/clients/token-transfers.ts// SDK — filters, comparison operators, ordering, pagination
const { data } = await client.subgraphs.queryTable(
"token-transfers",
"transfers",
{
sort: "_block_height",
order: "desc",
limit: 25,
filters: { sender: "SP1234...", "amount.gte": "1000000" },
},
);
// HTTP
// GET https://api.secondlayer.tools/api/subgraphs/token-transfers/transfers
// ?_sort=_block_height&_order=desc&_limit=25&sender=SP1234...