Getting Started

Quick start

A MarrowStack block is a TypeScript file. There is no CLI, no code generation, and no dependency on the MarrowStack package. Copy the file, run the migration, set env vars.

Prerequisites

  • Next.js 14 or 15 (App Router)
  • TypeScript 5+ with strict: true
  • Supabase project (free tier works)
  • Node.js 18+ or Bun 1.x

1. Sign in and copy

All blocks are free. Sign in at marrowstack.dev, open any block, and click Copy all files. The file contents are copied to your clipboard. Paste them into your project — no cloning required.

2. Run the SQL migration

Each block ships with a SQL migration. Run it in your Supabase project once, before starting the app. The migration creates the required tables, indexes, and RLS policies.

  1. Open Supabase Dashboard → SQL Editor.
  2. Paste the SQL from the MIGRATION constant at the top of the block file.
  3. Run it. RLS is enabled automatically.

3. Set environment variables

Required vars are documented at the top of each block file and in the block's docs page. The core vars shared by all blocks:

bash
# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJhbGc...  # never expose client-side

# For Solana blocks only
NEXT_PUBLIC_SOLANA_CLUSTER=devnet     # or mainnet-beta
SOLANA_AUTH_DOMAIN=yourdomain.com
SOLANA_TREASURY_ADDRESS=YourBase58PublicKey

4. Mount API routes

Each block exports named handler functions. Mount them as Next.js App Router route handlers.

typescript
// app/api/auth/[...nextauth]/route.ts
import { authOptions } from '@/lib/auth'
import NextAuth from 'next-auth'

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

5. Use the exports

All business logic is exported as async functions. Call them directly from server components, server actions, or route handlers.

typescript
import { getDashboardStats, requireAdmin } from '@/lib/admin'
import { getServerSession }                from 'next-auth'
import { authOptions }                     from '@/lib/auth'

export default async function AdminPage() {
  const session = await getServerSession(authOptions)
  requireAdmin(session)  // throws 401/403 if insufficient role

  const stats = await getDashboardStats()
  // ...
}