Secondlayer
September 13, 2026 · View on GitHub
Your app needs Stacks data that no public API has — your contract, your schema, your uptime. Today that means writing an indexer.
Secondlayer is the runtime instead: decoded chain data in your own database, backfilled from genesis, reorg-safe, kept current. Get tables and a REST API out of the box, or stream rows into your own schema — Postgres, SQLite, or anything you already run — and serve them however you already serve things.
The instance itself is Postgres plus one container, on your hardware.
See STRATEGY.md.
curl "http://127.0.0.1:3800/v1/index/events?event_type=ft_transfer&limit=5"
Quickstart
bun add -g @secondlayer/cli
secondlayer init --network mainnet
cd docker/oss && docker compose up -d
secondlayer observer --mode indexer --endpoint secondlayer:3700
secondlayer bootstrap --against <manifest>
secondlayer verify all --against <manifest>
# Index a contract into a typed, queryable Postgres table
export SL_API_URL=http://127.0.0.1:3800
secondlayer subgraphs scaffold SP1234ABCD.my-contract -o subgraphs/my-contract.ts
secondlayer subgraphs deploy subgraphs/my-contract.ts --start-block <recent-block>
secondlayer subgraphs query my-contract <table> --sort _block_height --order desc
A chain webhook fires on raw events with no subgraph:
secondlayer webhooks create amm-swaps \
--url https://my-app.com/webhook \
--trigger '{"type":"contract_call","contractId":"SP....amm","functionName":"swap-*"}'
Docs → self-host · CLI → packages/cli/README.md.
Read it from your instance
SDK default is http://127.0.0.1:3800 (or SL_API_URL).
import { SecondLayer } from "@secondlayer/sdk";
const sl = new SecondLayer();
const { rows, next_cursor, tip } = await sl.subgraphs.rows("my-contract", "<table>", {
order: "desc",
limit: 25,
});
curl "http://127.0.0.1:3800/v1/subgraphs/my-contract/<table>?_limit=25"
Pages are _id-keyset: pass ?cursor=<next_cursor> to resume, _order=asc|desc
for direction.
MCP — bunx -p @secondlayer/mcp secondlayer-mcp (default local API).
Set INSTANCE_TOKEN from secondlayer init for writes.
See MCP README.
Packages
Two TypeScript SDKs, one chooser: @secondlayer/sdk talks to this instance
(query subgraphs, manage webhooks); @secondlayer/stacks is low-level
chain primitives (Clarity decoding, reads). Most apps only need sdk.
| Package | Description |
|---|---|
@secondlayer/cli | secondlayer binary — init, bootstrap, verify, deploy |
@secondlayer/sdk | TypeScript SDK — Streams, Index, subgraphs, webhooks |
@secondlayer/mcp | MCP server — instance tools for agents |
@secondlayer/stacks | viem-style Stacks client — public/wallet, BNS |
@secondlayer/subgraphs | defineSubgraph() — schema, triggers, handlers |
@secondlayer/shared | Shared db, schemas, crypto helpers |
@secondlayer/api | REST API for the instance |
Self-host
git clone https://github.com/ryanwaits/secondlayer
cd secondlayer/docker/oss
secondlayer init --network mainnet
docker compose up -d
Development
bun install && bun run build && bun run test
Releases flow through Changesets:
bun run version to bump, bun run release to publish.
License
MIT