Embedded Dives: vibecodable data apps
Dives are code-based, fully customizable React components that can query MotherDuck, a serverless cloud data warehouse powered by DuckDB. Dives lets you build interactive dashboards, presentations, or even data-driven games, all fetching live data through SQL queries. Embedded in your app, Dives give you infinite flexibility over how data is presented, without the constraints of traditional BI tools.
This template gives you a deployable Next.js app where users can browse starter Dives, open full-page previews, and use AI chat to customize a Dive in place.
Features
- Starter dives: 3 example dives: slides, dashboard, and game mini-apps built on top of NYC 311 data, showed in the Dive gallery page with live previews.
- AI dive remix workflow: user can explore the underlying data and customize each dive through a natural language interface
- Auth options: public demo mode with anonymous sessions, password sign-in with one shared MotherDuck account, or password sign-in with each user providing a MotherDuck personal access token
- AI provider options: Anthropic, OpenAI, or Vercel AI Gateway through Vercel AI SDK
Demo auth note: included auth is for demo purposes. For production use cases, connect your own identity provider and authorization model before shipping.
Deploy
Click Deploy with Vercel. The clone flow provisions:
- MotherDuck integration, which can set
MOTHERDUCK_TOKEN - Supabase integration, which can set
POSTGRES_URL - This template's Vercel build command, which runs database migrations from
migrations/
If you do not install either integration, set the matching environment variable yourself before deploying.
After deploy, add at least one AI key in Vercel project settings, then redeploy:
ANTHROPIC_API_KEYOPENAI_API_KEYAI_GATEWAY_API_KEY
Manual deploy:
vercel linkvercel env pull .env.localvercel deploy
Local Development
git clone <your-repo-url>cd motherduck-divesnpm installcp .env.example .env.local
Run local Postgres:
docker run --name motherduck-dives-postgres \-e POSTGRES_PASSWORD=postgres \-e POSTGRES_DB=motherduck_dives \-p 5433:5432 \-d postgres:16
Set local database URL:
POSTGRES_URL=postgres://postgres:postgres@localhost:5433/motherduck_dives
Start app:
npm run dev
Open http://localhost:3000, choose a Dive, click Remix, and chat.
Useful commands:
npm run lintnpm exec tsc -- --noEmitnpm run buildnpm run build:with-migrate
Environment Variables
| Variable | Required | Description |
|---|---|---|
MOTHERDUCK_TOKEN | Yes | MotherDuck admin token used to provision service accounts and embed sessions |
POSTGRES_URL | Yes | Postgres connection string |
ANTHROPIC_API_KEY | One AI key required | Anthropic API key |
OPENAI_API_KEY | One AI key required | OpenAI API key |
AI_GATEWAY_API_KEY | One AI key required | Vercel AI Gateway API key |
AI_MODEL_ANTHROPIC | No | Anthropic model override, defaults to claude-sonnet-4-6 |
AI_MODEL_OPENAI | No | OpenAI model override, defaults to gpt-5.4 |
AI_MODEL_GATEWAY | No | AI Gateway model override, defaults to anthropic/claude-sonnet-4.6 |
Advanced overrides:
| Variable | Required | Description |
|---|---|---|
MOTHERDUCK_API_BASE | No | MotherDuck API URL override |
MOTHERDUCK_MCP_URL | No | MotherDuck MCP endpoint override |
MOTHERDUCK_PG_HOST | No | MotherDuck Postgres endpoint host override |
Auth Modes
Default mode is public demo mode. Visitors can preview shared starter Dives. First edit creates an isolated anonymous MotherDuck service account and cloned starter Dives for that browser session.
Password mode requires sign-in and uses one shared MotherDuck service account:
PASSWORD_AUTH_ENABLED=trueAUTH_SECRET=<long-random-string>MOTHERDUCK_SHARED_SERVICE_ACCOUNT_USERNAME=app_shared
Personal token mode requires sign-in and asks each user for their own MotherDuck personal access token:
PASSWORD_AUTH_ENABLED=trueAUTH_SECRET=<long-random-string>MOTHERDUCK_AUTH_MODE=personal_patMOTHERDUCK_PAT_ENCRYPTION_KEY=<long-random-string>
Auth mode options:
PASSWORD_AUTH_ENABLED: set totrueto require email/password sign-in.AUTH_SECRET: required when password auth is enabled. Use a long random string for NextAuth session signing.MOTHERDUCK_SHARED_SERVICE_ACCOUNT_USERNAME: optional shared MotherDuck service account username. Defaults toapp_shared.MOTHERDUCK_AUTH_MODE: set topersonal_patto require each signed-in user to provide a MotherDuck PAT.MOTHERDUCK_PAT_ENCRYPTION_KEY: required whenMOTHERDUCK_AUTH_MODE=personal_pat. Use a long random string to encrypt stored MotherDuck PATs.MOTHERDUCK_TOKEN_APP_NAME: optional app name shown on the MotherDuck token request page. Defaults tomotherduck-dives.AUTH_TRUSTED_ORIGINS: optional comma-separatedscheme://host[:port]values allowed for mutating requests behind proxies or custom origins.
Customize
Starter Dives
Edit starter Dive components:
dives/presentation-dive.tsxdives/dashboard-dive.tsxdives/game-dive.tsx
Starter metadata lives in app/_lib/dive-provisioning.ts.
AI Behavior
- Change model defaults in
app/_lib/chat/ai-provider.tsor set model env vars. - Change editing instructions in
app/_lib/chat/system-prompt.ts.
Data
Starter Dives use MotherDuck sample_data. To use your own data:
- Load or attach data in MotherDuck.
- Update SQL in the starter Dive files.
- If users should only see their own data, model access around MotherDuck shares, per-user databases, or row-level filters before production.
Production Checklist
- Replace demo auth with your app's identity provider.
- Add authorization around users, workspaces, Dives, chat history, and data access.
- Add rate limits to chat and provisioning routes.
- Keep
assertSameOrigin(request)on every mutating route. - Add monitoring for AI usage, MCP calls, embed session creation, and provisioning failures.
- Add cleanup for expired anonymous demo sessions and their MotherDuck service accounts before running a public demo at scale.
License
MIT


