Personal website and blog for Alex Swensen. Built with Next.js (App Router), React 19, Tailwind CSS v4, and TypeScript. Deployed on Vercel.
pnpm installcp .env.example .envFill in the required values:
| Variable | Description |
|---|---|
POSTGRES_PASSWORD |
Password for the local Postgres container |
DATABASE_URL |
Postgres connection string (defaults work for local dev) |
BETTER_AUTH_SECRET |
32+ char secret — generate with openssl rand -base64 32 |
BETTER_AUTH_URL |
Base URL of the app (e.g. http://localhost:3000) |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
Google OAuth credentials |
DISCORD_CLIENT_ID / DISCORD_CLIENT_SECRET |
Discord OAuth credentials |
For production, set DATABASE_URL to your Neon connection string and BETTER_AUTH_URL to your deployed domain.
This project uses PostgreSQL via Docker Compose, with a Neon-compatible WebSocket proxy so the same @neondatabase/serverless driver works locally and in production.
docker compose up -d| Service | Port | Purpose |
|---|---|---|
db |
5432 |
PostgreSQL 18 |
neon-proxy |
4444 |
WebSocket proxy (Neon driver compatibility) |
pnpm db:migrate| Command | Description |
|---|---|
pnpm db:generate |
Generate a new migration file from schema changes |
pnpm db:migrate |
Apply pending migrations |
pnpm db:push |
Push schema directly to the database (dev only, no migration files) |
pnpm db:studio |
Open Drizzle Studio to browse the database |
pnpm db:reset |
Schema files live in src/db/schema/. The auth tables (user, session, account, verification, two_factor) are managed by Better Auth and defined in src/db/schema/auth.ts.
pnpm devOpen http://localhost:3000 with your browser.
Authentication is handled by Better Auth.
- Email + password sign-up and sign-in
- Google and Discord OAuth
- Two-factor authentication (TOTP via authenticator app + one-time backup codes)
- Auth routes live under
/auth/sign-in,/auth/sign-up, and/auth/two-factor - The header shows Sign in / Register when logged out, and the user's name + Sign out when logged in
Each blog post has a comment section at /blog/[slug]. Authenticated users can post comments. Unauthenticated visitors see a prompt to sign in or register.
Comments API: GET /api/comments?slug=<slug> and POST /api/comments.
pnpm storybook # dev server on :6006
pnpm build-storybook # production buildAll components in src/components and src/components/ui have corresponding .stories.tsx files.
Push to main — Vercel deploys automatically. Set the environment variables listed above in the Vercel project settings.
Check out our Next.js deployment documentation for more details.