- Install Bun:
curl -fsSL https://bun.sh/install | bash - Install dependencies:
bun install
(Easier to get started, but you'll be working against real data, so be careful)
# Get environment variables
bunx vercel link
bunx vercel env pull
# Run against remote
bun run dev # Production database
bun run dev:dev # Development database(Somewhat trickier to set up)
- Install docker: Orbstack.dev or Docker desktop
- Start local supabase:
bun run supabase:local - Update .env.development.local with local supabase details:
bun run setup-local-env - Import data (Optional):
bun run sync-data-from-prod. This requires additional keys. - Run server using local supabase:
bun run dev:local
- Make your schema changes
- Option A: Via Supabase Studio (http://localhost:54323)
- Option B: Write SQL migrations manually
- Generate a migration
- From Studio changes:
npx supabase db diff --schema public --file your_migration_name - Manual:
npx supabase migration new your_migration_namethen edit the file
- From Studio changes:
- Apply migration locally:
npx supabase migration up
- Update local typescript types
bun run gen-types:local
- Test your changes
- Apply migrations to remote supabase projects when ready
# Link to target environment
npx supabase link --project-ref PROJECT_ID # fkousziwzbnkdkldjper for prod, oucjhqqretizqonyfyqu for dev
# Check what migrations will be applied
npx supabase migration list --linked
# Dry run to see what would happen and confirm its safety
npx supabase migration up --linked --dry-run
# Apply migrations
npx supabase migration up --linked
If you want Google Oauth to work locally, you should provide these values to your .env.development.local
SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_ID=your-client-id
SUPABASE_AUTH_EXTERNAL_GOOGLE_SECRET=your-secret
Setup for this requires:
- Creating a google cloud project and (enabling oauth)[https://console.cloud.google.com/apis/credentials]
- Creating Oauth2.0 credentials with
http://127.0.0.1:54321/auth/v1/callbackas an authorized reidrect URI
bunx supabase login
bun run gen-types # From prod
bun run gen-types:dev # From devAdmin status (access to /admin, adjusting user balances, approving grants,
transferring money between users, editing/restoring projects, etc.) is granted
by a hardcoded allowlist of email addresses — there is no database role or UI
toggle. The single source of truth is the ADMINS array in isAdmin() in
db/profile.ts. To make someone an admin, add their account's email there:
// db/profile.ts
const ADMINS = ['akrolsmir@gmail.com', 'hannah@manifund.org'] // ← add new admins hereThe email must match the address on their Manifund/Google account exactly
(it's compared against user.email from Supabase Auth).
After editing, commit and deploy — the change takes effect on the next deploy
(no migration or env change needed). Verify with bun run build.
stripe listen --forward-to localhost:3000/api/stripe-endpoints