A real-time chat app: rooms + DMs, OAuth via Convex Auth (GitHub/Google), typing indicators, online presence, emoji reactions, edit/delete, image attachments, and full-text search. UI is shadcn-based with dark mode by default.
-
Frontend: React 19 + Tailwind v4 + shadcn (new-york), bundled by Bun.
-
Backend: Convex (queries, mutations, file storage, full-text search, WebSocket subscriptions, the official
@convex-dev/presencecomponent). Auth:@convex-dev/authwith@auth/coreGitHub + Google providers (no third-party auth vendor).
bun install
# Start the Convex dev backend (writes CONVEX_URL etc. to .env.local)
bunx convex dev
# In a second terminal, run the SPA dev server (Bun, with HMR)
bun dev.env.local after the first run will look like:
CONVEX_DEPLOYMENT=... # written by convex dev
CONVEX_URL=http://127.0.0.1:3210
CONVEX_SITE_URL=http://127.0.0.1:3211
BUN_PUBLIC_CONVEX_URL=http://127.0.0.1:3210 # add manually for the browser
Note: only env vars prefixed with BUN_PUBLIC_ are exposed to the browser
bundle (see bunfig.toml). Set BUN_PUBLIC_CONVEX_URL to the same value as
CONVEX_URL.
In your Convex dashboard, set these env vars on your deployment:
AUTH_GITHUB_ID=...
AUTH_GITHUB_SECRET=...
AUTH_GOOGLE_ID=...
AUTH_GOOGLE_SECRET=...
SITE_URL=http://localhost:3000 # set automatically by `npx @convex-dev/auth`
Set the OAuth callback URLs in each provider's dashboard to:
<CONVEX_SITE_URL>/api/auth/callback/github
<CONVEX_SITE_URL>/api/auth/callback/google
(CONVEX_SITE_URL is shown by convex dev and stored in .env.local.)
- Push the repo to GitHub.
- In Convex dashboard, run
npx convex deploy --cmd 'echo skip'from your machine (or use the Convex GitHub integration) to provision a production deployment. Save its URL (e.g.https://<name>.convex.cloud). - In Vercel, import the project. Set:
- Build command:
bun run build - Output directory:
dist - Install command:
bun install - Env vars:
BUN_PUBLIC_CONVEX_URL=https://<name>.convex.cloud
- Build command:
- In Convex dashboard → Settings → Environment Variables, set production
values for
SITE_URL(your Vercel URL),AUTH_GITHUB_*,AUTH_GOOGLE_*, and add the production callback URLs to each OAuth app. vercel.jsonis included with a SPA rewrite so deep links work on refresh.
The browser opens a WebSocket directly to Convex, so Vercel's serverless limits don't apply to real-time traffic.
bun dev— Bun dev server with HMR on port 3000.bun run build— Static build todist/.bun start— Serve the built app from Bun (production-style, optional).bunx convex dev— Convex backend + codegen watcher.
frontend/
convex/ # Convex backend (schema, queries, mutations)
schema.ts
auth.ts auth.config.ts http.ts
convex.config.ts # mounts @convex-dev/presence component
lib/auth.ts # getCurrentUser, requireMember helpers
users.ts conversations.ts messages.ts reactions.ts files.ts
presence.ts typing.ts search.ts
src/
App.tsx # auth gate
frontend.tsx # providers (Theme, ConvexAuth, Toaster)
components/
theme-provider.tsx
auth/ # SignInScreen, UserMenu
chat/ # AppShell, Sidebar, ConversationView,
# MessageList/Item/Composer, ReactionBar,
# TypingIndicator, NewConversationDialog,
# SearchPalette
ui/ # shadcn primitives
hooks/useTyping.ts
lib/convex.ts utils.ts
vercel.json
build.ts # bun-based static build