Archimedes: Full-Stack Architect
Give me a lever and a place to stand, and I will scaffold the world. Production-ready Next.js with Bun, shadcn/ui, better-auth, Drizzle ORM, and SQLite.
Stack
| Layer | Tool | Purpose |
|---|---|---|
| Runtime | Bun | Package manager & JS runtime |
| Framework | Next.js (App Router) | React framework with SSR/RSC |
| UI | shadcn/ui + Tailwind CSS | Component library |
| Auth | better-auth | Self-hosted authentication |
| ORM | Drizzle ORM | Type-safe database access |
| Database | SQLite (via bun:sqlite) | Embedded database |
Scaffolding Workflow
Copy this checklist and track progress:
Task Progress:
- [ ] Step 1: Create Next.js project
- [ ] Step 2: Initialize shadcn/ui
- [ ] Step 3: Install dependencies
- [ ] Step 4: Set up environment variables
- [ ] Step 5: Configure Drizzle ORM + SQLite
- [ ] Step 6: Configure better-auth
- [ ] Step 7: Create auth API route
- [ ] Step 8: Create auth client
- [ ] Step 9: Push database schema
- [ ] Step 10: Add package.json scripts
Step 1: Create Next.js Project
Always start fresh. Use non-interactive mode with all defaults:
bun create next-app@latest <project-name> --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --turbopack --use-bun
Then cd into the project directory.
Step 2: Initialize shadcn/ui
bunx --bun shadcn@latest init -d
The -d flag uses defaults (New York style, Zinc color, CSS variables enabled). If the user wants customization, drop the -d flag.
Step 3: Install Dependencies
bun add better-auth drizzle-orm
bun add -D drizzle-kit @types/bun
Step 4: Set Up Environment Variables
Create .env.local:
BETTER_AUTH_SECRET=<generate-with-openssl-rand-base64-32>
BETTER_AUTH_URL=http://localhost:3000
DB_FILE_NAME=sqlite.db
Generate the secret:
openssl rand -base64 32
Add to .gitignore:
*.db
*.db-journal
Step 5: Configure Drizzle ORM + SQLite
Create src/db/index.ts — database connection:
import { drizzle } from "drizzle-orm/bun-sqlite";
import { Database } from "bun:sqlite";
import * as schema from "./schema";
const sqlite = new Database(process.env.DB_FILE_NAME!);
export const db = drizzle({ client: sqlite, schema });
Create src/db/schema/index.ts — re-export all schema files:
export * from "./auth";
Create src/db/schema/auth.ts — will be populated by better-auth CLI in Step 6.
Leave empty for now (placeholder):
// Generated by better-auth CLI — do not edit manually
Create drizzle.config.ts in project root:
import { defineConfig } from "drizzle-kit";
export default defineConfig({
out: "./drizzle",
schema: "./src/db/schema",
dialect: "sqlite",
dbCredentials: {
url: process.env.DB_FILE_NAME!,
},
});
Step 6: Configure better-auth
Create src/lib/auth.ts — server-side auth instance:
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db";
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "sqlite",
}),
emailAndPassword: {
enabled: true,
},
});
Generate the auth schema into Drizzle format:
bunx @better-auth/cli@latest generate --output src/db/schema/auth.ts
This populates src/db/schema/auth.ts with the required user, session, account, and verification tables.
Step 7: Create Auth API Route
Create src/app/api/auth/[...all]/route.ts:
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
export const { GET, POST } = toNextJsHandler(auth);
Step 8: Create Auth Client
Create src/lib/auth-client.ts — client-side auth:
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient();
export const { signIn, signUp, signOut, useSession } = authClient;
Step 9: Push Database Schema
For local development, use push for fast iteration:
bunx drizzle-kit push
For production workflows, use generate + migrate:
bunx drizzle-kit generate
bunx drizzle-kit migrate
Step 10: Add Package.json Scripts
Add these to package.json scripts:
{
"scripts": {
"db:push": "drizzle-kit push",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio"
}
}
Final Project Structure
<project-name>/
├── src/
│ ├── app/
│ │ ├── api/
│ │ │ └── auth/
│ │ │ └── [...all]/
│ │ │ └── route.ts # better-auth handler
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── components/
│ │ └── ui/ # shadcn components
│ ├── db/
│ │ ├── index.ts # drizzle connection
│ │ └── schema/
│ │ ├── index.ts # barrel export
│ │ └── auth.ts # better-auth tables
│ └── lib/
│ ├── auth.ts # better-auth server instance
│ ├── auth-client.ts # better-auth client instance
│ └── utils.ts # shadcn cn() utility
├── drizzle/ # migration files
├── drizzle.config.ts
├── .env.local
├── components.json # shadcn config
├── package.json
└── tsconfig.json
Verification
After scaffolding, verify the setup:
bun run dev
Then confirm:
- App loads at
http://localhost:3000 - Auth endpoint responds at
http://localhost:3000/api/auth/ok - Database file
sqlite.dbis created
Common Next Steps
After scaffolding, users typically want to:
- Add UI components:
bunx --bun shadcn@latest add button card input label - Build auth pages: Sign-in / sign-up forms using
signIn.email()andsignUp.email() - Protect routes: Use
auth.api.getSession()server-side - Add OAuth providers: GitHub, Google, etc. via better-auth social providers
- Add application schemas: New tables in
src/db/schema/
For detailed code templates and extension patterns, see reference.md.
