Baseline Rules

These are our recommended technologies and guidelines for completing bounties. Following these standards helps ensure quality, maintainability, and faster review times.

Choose Your Stack

Most bounties fall into one of two categories. Pick the right stack for the job.

Path 1 Most Projects

Supabase + Vercel

For most apps, this is all you need. Supabase gives you Postgres, auth, storage, and real-time out of the box.

+ Next.js (App Router)
+ Supabase (database, auth, storage)
+ Tailwind CSS + shadcn/ui
+ Vercel (deploy)

Use Supabase's client directly. Don't add Drizzle—it's unnecessary complexity.

Path 2 Custom Setup

Drizzle + Neon + Better Auth

For apps that need more control, complex queries, or specific database requirements.

+ Next.js (App Router)
+ Drizzle ORM (type-safe SQL)
+ Neon or PlanetScale (database)
+ Better Auth (authentication)
+ Tailwind CSS + shadcn/ui
+ Vercel (deploy)

Neon for Postgres, PlanetScale for MySQL (no foreign keys).

Always Use These

TypeScript

Strict mode enabled. No any.

Zod

Runtime validation for all external inputs.

pnpm

Package manager. Fast, disk-efficient.

Where to Store Data

Never use localStorage for app data

If it belongs in a database, put it in a database. localStorage is for non-essential UI preferences only (like sidebar collapsed state). It's not for user data, session state, shopping carts, or anything you'd be upset to lose.

Data TypeStore InWhy
Auth tokensHTTP-only cookiesCan't be stolen via XSS
User data, settingsDatabasePersists, syncs across devices
Shopping cartDatabase + cookie IDSurvives logout, device changes
Theme preferenceCookie (not localStorage)Available server-side, no flash
Sidebar collapsedlocalStorage (ok here)Non-essential UI state

Code Quality

Clean Code

  • Descriptive variable and function names
  • Small, focused functions (single responsibility)
  • Comment the "why", not the "what"
  • Delete dead code—don't comment it out

Type Safety

  • Never use any—use unknown with type guards
  • Derive types from schemas (Zod, Drizzle) instead of defining separately
  • Validate all external inputs with Zod on the server
  • Let TypeScript infer when obvious—don't over-annotate

Security

  • Validate and sanitize all user inputs on the server
  • Use parameterized queries (Supabase and Drizzle handle this)
  • Never commit secrets—use environment variables
  • Never trust client-side data—always validate server-side

API Design

REST Conventions

  • Nouns for resources: /users, not /getUsers
  • HTTP methods: GET (read), POST (create), PUT/PATCH (update), DELETE
  • Status codes: 200, 201, 400, 401, 403, 404, 500
  • Pagination for list endpoints

Error Responses

Return consistent error shapes:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid email format",
    "details": { "field": "email" }
  }
}

Performance

Do

  • Server Components by default in Next.js
  • Lazy load below-the-fold components
  • Optimize images with next/image
  • Index frequently queried columns
  • Use connection pooling

Avoid

  • N+1 queries—use joins or batch fetching
  • Fetching data you don't need
  • Blocking the main thread
  • Huge bundle sizes—code split

Submission Checklist

  • OK Code builds without errors (pnpm build)
  • OK All tests pass (pnpm test)
  • OK No linting errors (pnpm lint)
  • OK TypeScript strict mode passes
  • OK No secrets or credentials in the code
  • OK No app data stored in localStorage
  • OK All user inputs validated with Zod on the server
  • OK PR description explains the changes clearly