A Reddit-style community platform that runs entirely on Cloudflare.
No separate app servers. No managed Postgres elsewhere. No S3 account on another cloud. The app, database, media, AI, search vectors, bot protection, and edge rate limits all live on Cloudflare’s network.
Built end-to-end with Cursor (AI pair-programming), with human steering on architecture and product direction — a practical example of shipping a full product without leaving Cloudflare’s platform.
Source + deploy instructions. Fork it and deploy your own instance on Cloudflare.
- Cloudflare as the whole backend — Workers are versatile enough for a real social app: SSR UI, APIs, stateful coordination, SQL, object storage, embeddings, and abuse controls.
- Modern AI-assisted engineering — most of the implementation was written by an agent in Cursor; the result is meant to be readable, deployable, and honest about that workflow.
| Product | Role in red |
|---|---|
| Workers + OpenNext | Next.js app + custom edge entry (src/worker.ts) |
| D1 | Primary SQL database (users, posts, votes, DMs, …) |
| R2 | Media uploads |
| Durable Objects | Per-post vote aggregation (PostObject) |
| KV (optional) | Edge cache / challenge state (falls back to memory) |
| Vectorize + Workers AI | Post embeddings, recommendations, translation |
| Workers Rate Limiting | Cheap IP flood gates before Next/SSR |
| Turnstile | Human checks on auth and write paths |
| Workers Logs | Observability (observability in wrangler.jsonc) |
flowchart LR
Browser --> Worker["Worker / OpenNext"]
Worker --> D1[(D1)]
Worker --> R2[(R2)]
Worker --> DO["Durable Object\nPostObject"]
Worker --> KV[(KV)]
Worker --> AI["Workers AI"]
Worker --> VZ[Vectorize]
Worker --> TS[Turnstile]
- Communities, posts, comments, votes, profiles
- Auth (Better Auth) with email/password + username
- Search and AI-backed recommendations
- Direct messages and notifications
- Media uploads (R2)
- Ads + post analytics
- Admin / moderation tools
- Achievements, karma, badges, tags
- Content translation via Workers AI
- Sealed Protobuf API tunnel (
/i/api) with bot / PoW challenges - Personal API keys
Prerequisites: Node 22+, a Cloudflare account (AI / Vectorize are remote; D1 works locally).
git clone https://github.com/koval01/red.git
cd red
npm ci
cp .dev.vars.example .dev.vars
npm run db:reset:local # migrate + seed demo data
npm run dev # http://localhost:3000Seeded demo login (local only): alice / password123
Turnstile test keys in .dev.vars.example always pass locally. Replace them with your own widget keys for production.
| Script | Purpose |
|---|---|
npm run dev |
Next.js + Cloudflare bindings via OpenNext for Dev |
npm run preview |
OpenNext build + local Workers preview |
npm run deploy |
Build and deploy the Worker |
npm test |
Unit + Workers/integration tests |
npm run test:e2e:chromium |
Playwright smoke (Chromium) |
npm run db:migrate:local |
Apply D1 migrations locally |
npm run vectors:create |
Create the Vectorize index (remote) |
-
Create Cloudflare resources:
npx wrangler login npx wrangler d1 create red-db npx wrangler r2 bucket create red-media npm run vectors:create # Vectorize index red-posts (768 dims, cosine) # optional: npx wrangler kv namespace create CACHE npx wrangler kv namespace create CACHE --preview
-
Paste the returned IDs into
wrangler.jsonc(database_id, and KV ids if used). -
Set
vars.BETTER_AUTH_URLto your public origin and put your Turnstile site key invars.NEXT_PUBLIC_TURNSTILE_SITE_KEY. -
Add that same origin to
trustedOriginsinsrc/lib/auth.ts. -
Set secrets:
wrangler secret put BETTER_AUTH_SECRET wrangler secret put TURNSTILE_SECRET_KEY
-
Apply remote migrations, then deploy:
npx wrangler d1 migrations apply DB --remote npm run deploy
-
Attach a custom domain in the dashboard (Workers → Domains & Routes), or use
*.workers.dev.
NEXT_PUBLIC_*is baked at build time. Keep.env.local/ build env aligned with the Turnstile site key inwrangler.jsoncbeforenpm run deploy.- Speed Brain (zone Speed → Optimization) injects speculative prefeches that Cloudflare refuses for Worker routes (
cf-speculation-refused→ cosmetic Network-tab 503). Real navigations still return 200. Turn Speed Brain off for Worker apps if the noise bothers you. - Profile achievement sync is backgrounded for public views so Link-prefetch storms don’t burn Worker CPU.
- Single Worker — OpenNext handler and
PostObjectship together fromsrc/worker.ts. - Edge rate limits first — floods die before SSR/D1/AI can run.
- D1 + Kysely — schema in
migrations/; access viasrc/lib/db.ts. - Security — Turnstile, signed human cookies, challenge / PoW, sealed
/i/apiundersrc/lib/security/andsrc/lib/internal-api/.
GitHub Actions (.github/workflows/ci.yml) runs local D1 migrate/seed, typecheck, Vitest (unit + workers), and Playwright Chromium.
npm test
npm run test:e2e:install
npm run test:e2e:chromium- Next.js · OpenNext Cloudflare
- Better Auth · Kysely · Tailwind CSS
- Wrangler · Vitest · Playwright
- Cursor — primary implementation workflow
MIT — see LICENSE.
0 comments
log in to comment.