cloudflare-full-stack-integration

from jackspace/claudeskillz

ClaudeSkillz: For when you need skills, but lazier

8 stars2 forksUpdated Nov 20, 2025
npx skills add https://github.com/jackspace/claudeskillz --skill cloudflare-full-stack-integration

SKILL.md

Cloudflare Full-Stack Integration Patterns

Production-tested patterns for React + Cloudflare Workers + Hono + Clerk authentication.

When to Use This Skill

Use this skill when you need to:

  • Connect a React frontend to a Cloudflare Worker backend
  • Implement authentication with Clerk in a full-stack app
  • Set up API calls that automatically include auth tokens
  • Fix CORS errors between frontend and backend
  • Prevent race conditions with auth loading
  • Configure environment variables correctly
  • Set up D1 database access from API routes
  • Create protected routes that require authentication

What This Skill Provides

Templates

Frontend (templates/frontend/):

  • lib/api-client.ts - Fetch wrapper with automatic token attachment
  • components/ProtectedRoute.tsx - Auth gate pattern with loading states

Backend (templates/backend/):

  • middleware/cors.ts - CORS configuration for dev and production
  • middleware/auth.ts - JWT verification with Clerk
  • routes/api.ts - Example API routes with all patterns integrated

Config (templates/config/):

  • wrangler.jsonc - Complete Workers configuration with bindings
  • .dev.vars.example - Environment variables setup
  • vite.config.ts - Cloudflare Vite plugin configuration

References (references/):

  • common-race-conditions.md - Complete guide to auth loading issues

Critical Architectural Insights

1. @cloudflare/vite-plugin Runs on SAME Port

Key Insight: The Worker and frontend run on the SAME port during development.

// ✅ CORRECT: Use relative URLs
fetch('/api/data')

// ❌ WRONG: Don't use absolute URLs or proxy
fetch('http://localhost:8787/api/data')

Why: The Vite plugin runs your Worker using workerd directly in the dev server. No proxy needed!

2. CORS Must Be Applied BEFORE Routes

// ✅ CORRECT ORDER
app.use('/api/*', cors())
app.post('/api/data', handler)

// ❌ WRONG ORDER - Will cause CORS errors
app.post('/api/data', handler)
app.use('/api/*', cors())

3. Auth Loading is NOT a Race Condition

Most "race conditions" are actually missing isLoaded checks:

// ❌ WRONG: Calls API before token ready
useEffect(() => {
  fetch('/api/data') // 401 error!
}, [])

// ✅ CORRECT: Wait for auth to load
const { isLoaded, isSignedIn } = useSession()
useEffect(() => {
  if (!isLoaded || !isSignedIn) return
  fetch('/api/data') // Now token is ready
}, [isLoaded, isSignedIn])

4. Environment Variables Have Different Rules

Frontend (Vite):

  • MUST start with VITE_ prefix
  • Defined in .env file
  • Access: import.meta.env.VITE_VARIABLE_NAME

Backend (Workers):

  • NO prefix required
  • Defined in .dev.vars file (dev) or wrangler secrets (prod)
  • Access: env.VARIABLE_NAME

5. D1 Bindings Are Always Available

D1 is accessed via bindings - no connection management needed:

// ✅ CORRECT: Direct access via binding
const { results } = await env.DB.prepare('SELECT * FROM users').run()

// ❌ WRONG: No need to "connect" first
const connection = await env.DB.connect() // This doesn't exist!

Step-by-Step Integration Guide

Step 1: Project Setup

# Create project with Cloudflare Workers + React
npm create cloudflare@latest my-app
cd my-app

# Install dependencies
npm install hono @clerk/clerk-react @clerk/backend
npm install -D @cloudflare/vite-plugin @tailwindcss/vite

Step 2: Configure Vite

Copy templates/config/vite.config.ts to your project root.

Key points:

  • Includes cloudflare() plugin
  • No proxy configuration needed
  • Sets up path aliases for clean imports

Step 3: Configure Wrangler

Copy templates/config/wrangler.jsonc to your project root.

Update:

  • Replace name with your app name
  • Add D1/KV/R2 bindings as needed
  • Set run_worker_first: ["/api/*"] for API routes

Step 4: Set Up Environment Variables

Create .dev.vars (gitignored):

CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
CLERK_SECRET_KEY=sk_test_xxxxx

Create .env for frontend:

VITE_CLERK_PUBLISHABLE_KEY=pk_test_xxxxx

Step 5: Add CORS Middleware

Copy templates/backend/middleware/cors.ts to your backend.

Apply in your main worker file:

import { corsMiddleware } from './middleware/cors'

app.use('/api/*', (c, next) => corsMiddleware(c.env)(c, next))

CRITICAL: Apply this BEFORE defining routes!

Step 6: Add Auth Middleware

Copy templates/backend/middleware/auth.ts to your backend.

Apply to protected routes:

import { jwtAuthMiddleware } from './middleware/auth'

app.use('/api/protected/*', jwtAuthMiddleware(c.env.CLERK_SECRET_KEY))

Step 7: Set Up API Client

Copy templates/frontend/lib/api-client.ts to your frontend.

Use in your App component:

import { useApiClient } from '@/lib/api-client'

function App() {
  useApiClient() // Set up token access
  return <YourApp />
}

Step 8: Create Protected Routes

Copy `templat

...

Read full content

Repository Stats

Stars8
Forks2
LicenseMIT License