Build your first Sanity page-builder block, step by step
A hands-on walkthrough: go from an empty folder to a live, typed, editor-ready page-builder block in Turbo Start Sanity without missing a single wire.
Adding a block to the Turbo Start Sanity page-builder is one of those tasks that feels fiddly until you have done it once. There are seven touch points, and skipping any one leaves the block half-wired. This walkthrough builds a simple "callout" block end to end so you can see every step in context.
What we are building
A callout: a short heading, a body paragraph and a tone (info or warning). Nothing fancy — the point is the wiring, not the block.
1. Create the block folder
Every block lives in its own directory under the blocks package with three files. Start with the schema:
2. Register it so the Studio sees it
Export the schema from the package entry and add it to blockSchemas. The Studio merges that array into its schema types and into the page-builder array definition, so the block appears in the "add block" menu with no further wiring on the Studio side.
3. Regenerate types
Schema changed, so the generated types are now stale. Run the extract pass, then the type pass:
Do them in that order. Generating types against a schema you never re-extracted is the classic way to spend an hour debugging a type that was correct all along.
4. Add a GROQ projection
Co-locate the projection with the block, and list the fields explicitly rather than spreading everything:
Then include it in the shared pageBuilderFragment so the block's data is actually fetched with the rest of the page.
5. Build the component
6. Register it in the renderer
Add a case to renderBlockComponent in the web app's page-builder, casting to the generated type so a future rename breaks the build instead of shipping any:
An unregistered block renders a visible "component not found" placeholder in preview, so if you forget this step you will notice immediately.
7. Add a Markdown serializer
The last step is the one people miss. Turbo Start Sanity serves every page as Markdown for agents, and each block needs a serializer or it renders blank in .md output:
Wire it into the block-to-Markdown dispatcher, and add a test asserting no JSX leaks into the output.
The payoff
Seven steps, but every one has a loud failure mode: a rename breaks the build, a missing serializer shows up in Markdown, an unregistered block shows a placeholder. Once you have felt the rhythm once, the tenth block takes ten minutes — and an AI assistant can follow the exact same checklist to scaffold the next one for you.