KahWee - Web Development, AI Tools & Tech Trends

Expert takes on AI tools like Claude and Sora, modern web development with React and Vite, and tech trends. By KahWee.

Building a Modern Full-Stack Web Application - Part 2

This post covers deployment and production workflows. Part 1 covered the tech stack and architecture.

Hosting & Deployment

Infrastructure

Fly.io hosts the application. It scales to zero when idle and runs database migrations during deployment.

Cloudflare handles CDN, DDoS protection, and SSL.

Neon hosts PostgreSQL with serverless auto-scaling, database branching for dev/staging, point-in-time recovery, and connection pooling.

Docker Multi-Stage Builds

The application uses multi-stage builds for optimization:

FROM node:24-alpine AS base
WORKDIR /app

FROM base AS deps
COPY package.json package-lock.json ./
RUN npm ci --only=production

FROM base AS build
COPY . .
RUN npm run build

FROM base AS runtime
COPY --from=build /app/build ./build
COPY --from=deps /app/node_modules ./node_modules
EXPOSE 3000
CMD ["npm", "start"]

Development Workflow

# Development
npm run dev        # Start development server
npm run test       # Run tests
npm run typecheck  # Type checking

# Database
npm run db:studio  # Visual database management
npm run db:seed    # Populate with sample data
npm run db:migrate # Apply schema changes

Code Quality Standards

The project uses ESLint with React and TypeScript rules, Prettier for formatting, strict TypeScript with noUncheckedIndexedAccess, Husky for git hooks, Vitest for unit tests, and Playwright for E2E testing.

Database Development with Drizzle Kit

Tip

Use db:push for quick development iteration, but always use db:generate and db:migrate for production changes to maintain migration history.

Schema changes follow a structured approach:

# 1. Edit app/db/schema.ts
# 2. Generate migration
npm run db:generate

# 3. Apply migration
npm run db:migrate

# Development workflow
npm run db:push   # Quick schema sync (dev only)
npm run db:studio # Visual database UI
npm run db:reset  # Clean database reset

Performance

Vite delivers sub-second HMR, tree shaking, route-based code splitting, and image compression.

Drizzle ORM caches query plans with prepared statements and pools connections. Type-safe migrations prevent runtime errors.

Catalyst UI gave us high-quality components without overhead. Fly.io reduced operational complexity to near zero.

Caution

Run db:generate and db:migrate before deploying, never db:push. Using db:push in production skips migration history and makes rollbacks impossible.

The deployment pipeline runs tests on every push, checks types, runs migrations during deploy, and rolls back on failure. React Router v7, Drizzle ORM, better-auth, and Fly.io together make a stack I'd pick again.