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.
Supabase + Vercel
For most apps, this is all you need. Supabase gives you Postgres, auth, storage, and real-time out of the box.
Use Supabase's client directly. Don't add Drizzle—it's unnecessary complexity.
Drizzle + Neon + Better Auth
For apps that need more control, complex queries, or specific database requirements.
Neon for Postgres, PlanetScale for MySQL (no foreign keys).
Always Use These
Strict mode enabled. No any.
Runtime validation for all external inputs.
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 Type | Store In | Why |
|---|---|---|
| Auth tokens | HTTP-only cookies | Can't be stolen via XSS |
| User data, settings | Database | Persists, syncs across devices |
| Shopping cart | Database + cookie ID | Survives logout, device changes |
| Theme preference | Cookie (not localStorage) | Available server-side, no flash |
| Sidebar collapsed | localStorage (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—useunknownwith 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