-
Install PNPM
# macOS brew add pnpm # Linux npm install -g pnpm
-
Install dependencies
pnpm install
-
Run Docker
docker compose up --build -d
For local testing or development few changes are required in
.env. instead of making changes to.env. create a.env.localBETTER_AUTH_URL=http://localhost:3002/api/v1/auth # Local backend endpoint NODE_ENV = "development"
docker compose --env-file .env.local up --build
-
-druns containers in detached mode. -
--buildensures the image is built or rebuilt as needed.
✅ Note: If you face migration errors locally, purge local Docker volumes (local only!) to reset the DB: For Server use the method decribed in at Drizzle Migration Creation / Error Fix in next section
docker compose down --volumes
-
-
DB Schemas:
db/schema→ main DB table definitionsdrizzle→ Drizzle migrations & configs
-
Better Auth Schema Generation
npx @better-auth/cli generate
-
Drizzle Studio Stop local PostgreSQL if running:
brew services stop postgresql pnpm drizzle-kit studio
-
Drizzle Migration Creation / Error Fix
- Fresh Server
- Make sure the docker container postgres is running.
- Run
db:generatescript and then run db:migrate to create and apply the schema migrations.
- Database Volume Exists
-
Delete drizzle folder if migration errors occur. (NOTE: Do not delete if these error occur due to value type issues. Instead fix the issues)
-
Run
db:pullscript which will create the following:drizzle/schema.tsdrizzle/relations.tsdrizzle/0000_*.sqldrizzle/meta/0000_*.jsondrizzle/meta/_journal.json -
Delete both
drizzle/0000_*.sqldrizzle/meta/0000_*.json -
Edit
drizzle/meta/_journal.jsonand delete the entries for idx:0{ "version": "7", "dialect": "postgresql", "entries": [ { "idx": 0, "version": "7", "when": 1754329815357, "tag": "0000_*", "breakpoints": true } ] }- Run
db:generatescript and thendb:migrate
- Run
| Command | When to Use | What It Does |
|---|---|---|
drizzle-kit generate |
When you change your schema | Generates a new SQL migration file based on changes in your Drizzle schema |
drizzle-kit migrate |
When you want to apply generated migrations to the database | Executes SQL migrations that were previously generated to bring your DB up to date |
drizzle-kit pull |
When you want to reverse engineer the DB schema into Drizzle format | Introspects an existing database and generates Drizzle schema.ts, relations.ts, and a SQL snapshot |
drizzle-kit push |
When you want to push schema directly to the DB (without migrations) | Pushes your current Drizzle schema directly to the database — skips the SQL migration process |
drizzle-kit studio |
When you want to visually inspect and browse your database | Spins up a local instance of Drizzle Studio for interactive DB browsing via a browser UI |
drizzle-kit check |
When you want to verify migration consistency and avoid race conditions | Scans generated migrations to detect possible race conditions or inconsistencies |
drizzle-kit up |
When you want to upgrade snapshot files after changes | Updates schema snapshots for previously generated migrations — useful after reordering or patching |
All routes must use Zod for both request and response schemas. Combine
it with
fastify-type-provider-zod
for:
- Fully typed handlers
- Auto-generated OpenAPI docs
Example Response Schema
import { z } from 'zod';
export const SuccessResponseSchema = z.object({
statusCode: z.number().default(200),
message: z.string(),
data: z.unknown().optional(),
});
// Generic version for type-safe data
export const createSuccessResponseSchema = <T extends z.ZodTypeAny>(
dataSchema: T
) =>
SuccessResponseSchema.extend({
data: dataSchema,
});Example Fastify Route
fastify.withTypeProvider<ZodTypeProvider>().route({
url: '/',
method: 'GET',
schema: {
querystring: ProfilePaginationQuerySchema,
response: {
200: createSuccessResponseSchema(z.array(z.object({ id: z.string() }))),
400: ErrorResponseSchema,
401: ErrorResponseSchema,
},
},
preHandler: authMiddleware,
handler: listProfiles,
});-
Auth Reference:
GET backend_endpoint/api/v1/auth/reference
-
Full API Reference:
GET backend_endpoint/api/v1/reference
-
Quick Getting Started:
GET backend_endpoint/api/v1/docs/getting-started
| Code | Status | When to Use | Response Body Should Include |
|---|---|---|---|
| 200 | OK | Successful GET requests | Requested data |
| 201 | Created | Successful resource creation | Created resource + Location header |
| 202 | Accepted | Async processing started | Processing status |
| 204 | No Content | Successful request with no body | Empty body |
| 400 | Bad Request | Client-side validation errors | Error details |
| 401 | Unauthorized | Missing/invalid authentication | WWW-Authenticate header |
| 403 | Forbidden | Insufficient permissions | Optional explanation |
| 404 | Not Found | Resource doesn't exist | Optional error details |
| 500 | Internal Server Error | Server-side failure | Optional error details |
- Use Zod for all request & response schemas.
- Use
--env-file .env.*custom env for custom environments. - Change the env keys before making the project opensource.