Hello! Thank you for checking out this project. If you like what you see and want to see more production-ready projects and blog posts about those projects, check out my personal site: oscargabriel.dev.
Better-Cloud is a comprehensive full-stack application demonstrating modern web development on Cloudflare's edge platform. This production-ready web app showcases real-time features, user authentication, and persistent data management using Cloudflare Workers, Durable Objects, D1, and KV, making use of Alchemy for its infrastructure-as-code configuration.
- π’ Global Counter: Real-time synchronized counter with persistent state
- π Guestbook: Traditional guestbook with user profiles and country field
- π€ User Authentication: Email OTP and social OAauth login (Google, GitHub)
- π Real-time Updates: WebSocket connections with hibernation API
- π Connection Monitoring: Live connection count tracking
- Application Features
- Tech Stack
- Project Structure
- Database Schema
- Durable Objects
- Authentication
- Getting Started
- License
- ASCII banner header
- Real-time API health check with tRPC
- Global State Management: SQLite-backed persistent counter
- Real-time Synchronization: WebSocket updates across all users
- Rich Metrics: Tracks total increments, decrements, last updater
- Connection Status: Live WebSocket connection monitoring
- Technical Diagrams: Interactive flow charts explaining the architecture
- User Messages: Create and view community messages
- Profile Integration: Automatic name population from user profiles
- Profile Settings: Update display name and preferences
- Session Management: View and terminate sessions on other devices
- Email OTP: Passwordless authentication via verification codes
- Social OAuth: Google and GitHub provider integration
- React 19: Latest React with concurrent features
- TypeScript: Full type safety throughout the application
- Vite: Fast development builds and hot module replacement
- TanStack Router: File-based routing with type-safe navigation
- TanStack Query: Server state management and caching
- TanStack Form: Type-safe form validation and handling
- Tailwind CSS v4: Modern utility-first styling
- shadcn/ui: Accessible component library
- Sonner: Toast notifications
- Cloudflare Workers: Serverless edge computing platform
- Hono: Lightweight web framework for Workers
- tRPC: End-to-end type-safe API with client-server sync
- Zod: Runtime type validation and schema parsing
- Cloudflare D1: Distributed SQLite database
- Drizzle ORM: Type-safe database queries and migrations
- Cloudflare KV: Key-value storage for sessions and caching
- Better Auth: Modern authentication with email OTP and OAuth
- Resend: Transactional email delivery
- Durable Objects: Stateful serverless objects with strong consistency
- WebSocket Hibernation API: Cost-effective real-time connections
- SQLite Storage: ACID transactions within Durable Objects
- Connection Pooling: Efficient WebSocket connection management
- Bun: Fast package manager and JavaScript runtime
- Biome: Modern linting and formatting (replaces ESLint + Prettier)
- Alchemy: Infrastructure-as-code for Cloudflare resources
- Wrangler: Cloudflare Workers development and deployment CLI
better-cloud/
βββ src/
β βββ client/ # React frontend application
β β βββ components/ # Reusable UI components
β β β βββ navbar/ # Header, theme toggle, user menu
β β β βββ ui/ # shadcn/ui component library
β β βββ hooks/ # Custom React hooks
β β β βββ use-counter-query.ts # Counter state management
β β β βββ use-dual-websocket.ts # WebSocket connections
β β βββ lib/ # Client-side utilities
β β β βββ auth-client.ts # Better Auth client setup
β β β βββ trpc-client.ts # tRPC client configuration
β β β βββ theme-provider.tsx # Dark/light theme context
β β βββ routes/ # File-based routing (TanStack Router)
β β β βββ _authLayout/ # Authentication pages
β β β β βββ sign-in.tsx # Email OTP and social login
β β β βββ _protectedLayout/ # Authenticated user pages
β β β β βββ counter.tsx # Global counter demo
β β β β βββ guestbook.tsx # Community guestbook
β β β β βββ profile.tsx # User profile management
β β β βββ __root.tsx # Root layout component
β β β βββ index.tsx # Landing page
β β βββ routeTree.gen.ts # Auto-generated route definitions
β β
β βββ server/ # Cloudflare Workers backend
β βββ db/ # Database layer
β β βββ schema/ # Drizzle ORM schemas
β β β βββ auth.ts # Authentication tables
β β β βββ guestbook.ts # Guestbook messages
β β βββ migrations/ # Database migration files
β β βββ index.ts # Database connection setup
β βββ durable-objects/ # Stateful serverless objects
β β βββ counter.ts # Global counter with SQLite
β β βββ connection-counter.ts # WebSocket connection tracking
β βββ lib/ # Server-side utilities
β β βββ auth.ts # Better Auth configuration
β β βββ context.ts # tRPC context setup
β β βββ types.ts # Shared TypeScript types
β βββ routers/ # tRPC API routes
β β βββ counter.ts # Counter operations
β β βββ guestbook.ts # Guestbook CRUD
β β βββ user.ts # User profile management
β β βββ index.ts # Router composition
β βββ index.ts # Worker entry point
β
βββ types/ # Global TypeScript definitions
β βββ env.d.ts # Alchemy augmented env types
β βββ vite.d.ts # Vite types
βββ public/ # Static assets
βββ alchemy.run.ts # Infrastructure-as-code (Alchemy)
βββ vite.config.ts # Vite configuration
βββ drizzle.config.ts # Database migration config
βββ biome.json # Linting and formatting rules
βββ package.json # Dependencies and scripts
The application uses Cloudflare D1 (distributed SQLite) with Drizzle ORM for type-safe database operations.
Command | Description |
---|---|
bun db:generate |
Generate migration files from schema changes |
bun db:push |
Push schema changes directly (development only) |
bun db:migrate |
Apply pending migrations to database |
bun db:studio |
Launch Drizzle Studio for local database |
bun db:studio:prod |
Launch Drizzle Studio for production database |
Durable Objects provide stateful, globally-consistent serverless computing with persistent storage and real-time WebSocket capabilities.
State Management
- Persistent counter value with increment/decrement operations
- Comprehensive metrics: total increments, decrements, last updater, timestamps
- SQLite-backed storage with ACID transaction guarantees
- Automatic state restoration after hibernation
WebSocket Features
- Real-time updates broadcast to all connected clients
- Hibernation API for cost-effective WebSocket connections
- Support for up to 32,768 concurrent connections per object
- Ping/pong keepalive and connection health monitoring
API Endpoints
GET /
- Retrieve current counter state and metricsPOST /increment
- Increment counter with optional amount and usernamePOST /decrement
- Decrement counter with optional amount and usernameWebSocket
- Real-time counter updates and connection management
Connection Tracking
- Real-time monitoring of active WebSocket connections
- Automatic count updates when clients connect/disconnect
- Broadcast connection count changes to all subscribers
- Hibernation-optimized for zero idle costs
Use Cases
- Live user count display
- Connection health monitoring
- Real-time presence indicators
- System load monitoring
Cost Efficiency
- Hibernation eliminates memory charges during idle periods
- Pay only for active compute time and storage
- Automatic wake-up on incoming requests (sub-millisecond latency)
Strong Consistency
- Single object instance processes all operations sequentially
- No race conditions or eventual consistency issues
- ACID transactions within SQLite storage
Global Performance
- Deployed to Cloudflare's global edge network
- Automatic migration to optimal data center locations
- Sub-100ms response times worldwide
Better Auth provides secure, modern authentication with multiple sign-in methods and session management.
Email OTP (One-Time Password)
- Passwordless authentication via email verification codes
- 6-digit OTP codes sent via Resend email service
Social OAuth Providers
- Automatic profile creation and linking
- Secure token management with refresh capabilities
Storage Architecture
- Primary Storage: User accounts and sessions in Cloudflare D1 database
- Secondary Storage: Session caching in Cloudflare KV for fast access
- Cross-subdomain Support: Shared sessions across
*.example.com
Security Features
- Secure HTTP-only cookies with SameSite protection
- Rate limiting on authentication attempts
- IP address and user agent tracking
- Automatic session expiry and cleanup
- Sign In: User enters email or clicks social provider
- Verification: OTP sent via email OR OAuth redirect to provider
- Account Creation: New users automatically get profiles created
- Session Establishment: Secure session created with KV caching
- Profile Access: User redirected to protected routes with full access
This application is configured to handle different domain configurations between development and production environments:
Development Environment (Cross-Domain)
- Frontend:
http://localhost:5173
- Backend:
http://localhost:8787
Production Environment (Cross-Subdomain)
- Frontend:
https://example.com
- Backend:
https://api.example.com
CUSTOM_WEB_DOMAIN & CUSTOM_API_DOMAIN These variables define your production domain configuration:
# Production domains (used by Alchemy for SSL/DNS setup)
CUSTOM_WEB_DOMAIN=example.com # Your main frontend domain
CUSTOM_API_DOMAIN=api.example.com # Your API backend subdomain
TRUSTED_ORIGINS Configuration This variable controls which origins Better Auth accepts requests from. It must be properly formatted as a comma-separated string that gets parsed into an array:
# Development
TRUSTED_ORIGINS=http://localhost:5173,http://localhost:8787
# Production
TRUSTED_ORIGINS=https://example.com,https://api.example.com
Important: The TRUSTED_ORIGINS
environment variable must be a comma-separated string without spaces. The application parses this using env.TRUSTED_ORIGINS?.split(",")
to create an array for Better Auth.
The authentication system uses different cookie settings based on the environment:
Development Settings (ALCHEMY_STAGE=dev
)
defaultCookieAttributes: {
sameSite: "none", // Required for cross-domain cookies
}
crossSubDomainCookies: {
enabled: false, // Not needed for different domains
}
trustedOrigins: [
"http://localhost:5173",
"http://localhost:8787"
]
Production Settings (ALCHEMY_STAGE=prod
)
defaultCookieAttributes: {
sameSite: "lax", // Safer for same domain, different subdomains
}
crossSubDomainCookies: {
enabled: true, // Share cookies across *.example.com
domain: "example.com" // Parent domain for subdomain sharing
}
trustedOrigins: [
"https://example.com",
"https://api.example.com"
]
Development Cross-Domain Issues
- Different ports/domains (
localhost:5173
βlocalhost:8787
) requiresameSite: "none"
- Browsers block cross-domain cookies with
sameSite: "lax"
by default - Must use
credentials: "include"
on all client requests
Production Cross-Subdomain Benefits
- Same parent domain allows
sameSite: "lax"
for better security - Cookies automatically shared across
*.example.com
subdomains - More secure than
sameSite: "none"
while maintaining functionality
All authentication endpoints are available under /auth/*
:
/auth/sign-in/email
- Email OTP initiation/auth/sign-in/google
- Google OAuth redirect/auth/sign-in/github
- GitHub OAuth redirect/auth/sign-out
- Session termination/auth/callback/*
- OAuth return endpoints
- Bun v1.2+ - Fast JavaScript runtime and package manager
- Node.js v18+ - Alternative runtime (if not using Bun)
- Cloudflare Account - For Workers, D1, KV, and domain management
- Wrangler CLI - Cloudflare development tool:
npm install -g wrangler
Local Development Environment
Create .env.dev.example
β .env.dev
with:
VITE_CLIENT_URL=http://localhost:5173
VITE_SERVER_URL=http://localhost:8787
TRUSTED_ORIGINS=http://localhost:5173
BETTER_AUTH_URL=http://localhost:8787
BETTER_AUTH_SECRET=your-secret-key
GOOGLE_CLIENT_ID=your-google-oauth-id
GOOGLE_CLIENT_SECRET=your-google-oauth-secret
GITHUB_CLIENT_ID=your-github-oauth-id
GITHUB_CLIENT_SECRET=your-github-oauth-secret
RESEND_API_KEY=your-resend-key
CUSTOM_WEB_DOMAIN=localhost:5173
CUSTOM_API_DOMAIN=localhost:8787
Production Environment
Create .env.prod.example
β .env.prod
with:
VITE_CLIENT_URL=https://example.com
VITE_SERVER_URL=https://api.example.com
TRUSTED_ORIGINS=https://example.com,https://api.example.com
BETTER_AUTH_URL=https://api.example.com
BETTER_AUTH_SECRET=your-production-secret-key
GOOGLE_CLIENT_ID=your-google-oauth-id
GOOGLE_CLIENT_SECRET=your-google-oauth-secret
GITHUB_CLIENT_ID=your-github-oauth-id
GITHUB_CLIENT_SECRET=your-github-oauth-secret
RESEND_API_KEY=your-resend-key
CUSTOM_WEB_DOMAIN=example.com
CUSTOM_API_DOMAIN=api.example.com
# Install dependencies
bun install
# Generate database migrations (if needed)
bun db:generate
# Push database schema to D1
bun db:push
Single Command Setup (Recommended)
# Start both frontend and backend with Alchemy
bun a:dev # β Frontend: http://localhost:5173, Backend: http://localhost:8787
Why Alchemy Dev Server?
- Unified Environment: Single command starts both Vite frontend and Workers backend
- Proper Database Integration: Uses the D1 database created by alchemy state stored in
.alchemy/
directory - Resource Management: Automatic setup of KV, Durable Objects, and other Cloudflare resources
Development Commands
bun check # Lint and format code with Biome
bun typecheck # TypeScript type checking
bun db:studio # Launch database browser interface
# Build for production
bun build
# Preview production build locally
bun preview # β http://localhost:4173
Option 1: Alchemy (Recommended)
# Deploy with Alchemy IaC
bun a:deploy # Deploy to production
Option 2: Direct Wrangler
# Deploy directly to Cloudflare
bunx wrangler deploy
Alchemy Configuration (alchemy.run.ts
)
- Declarative Resources: D1 database, KV namespaces, Durable Objects
- Custom Domains: Automatic DNS and SSL certificate management
- Environment Management: Separate dev/prod configurations
- Resource Adoption: Import existing Cloudflare resources
Cloudflare Resources Created:
- Worker: Main application server
- D1 Database: User data and guestbook messages
- KV Namespace: Session storage and caching
- Durable Objects: Counter and connection tracking
- Custom Domains: Production domain with SSL
MIT License