Build Guide
How to Build a Chat App
Building a chat app in 2026 takes 2 days with the right stack — the hard part is handling concurrent connections, not the UI.
Real-time messaging is one of the most requested features in every product category. Build a chat app and you'll understand WebSockets, presence detection, message queues, and push notifications.
Data model
The core tables you'll need before writing any UI.
Build order
The sequence that minimises rewrites — build in this order.
Static message list UI
Build the message list and input box with hardcoded messages. Focus on layout — message bubbles, timestamps, sender avatars. No logic yet.
Set up Supabase Realtime
Create the messages table and subscribe to inserts using supabase.channel(). Send a message via INSERT and watch it appear in real time. This is the core of the app.
Add auth and user presence
Add Clerk or Supabase Auth. Create a users table. Track online presence by updating last_seen_at every 30 seconds and showing a green dot for users active in the last 2 minutes.
Build DM and group rooms
Create the rooms and room_members tables. Add a room sidebar. For DMs, find or create a room with exactly the two user IDs. For groups, allow adding multiple members.
Read receipts and typing indicators
Track last_read_at per room_member and update it when the user scrolls to the bottom. For typing, use a Supabase Realtime broadcast channel (not database) — ephemeral, no DB writes.
File and image sharing
Upload files to Supabase Storage or Cloudinary. Store the URL in the message content field with a type of "image" or "file". Render images inline, files as download links.
Push notifications
Use Expo Notifications (mobile) or the Web Push API (browser). Store device tokens per user. Send a push when a new message arrives in a room the user is not currently viewing.
Build it with AI — Architect Prompt
Paste this into Claude, Cursor, Windsurf, or any AI coding tool. It includes the full context of this guide — data model, build order, and pitfalls — so the AI starts with everything it needs.
<context> App: Chat App Difficulty: Intermediate Estimated build time: 3–7 days Data model: User: id, username, avatar_url, last_seen_at Room: id, name, type (direct/group), created_by, created_at RoomMember: room_id, user_id, joined_at, last_read_at Message: id, room_id, user_id, content, type (text/image/file), created_at, edited_at Reaction: message_id, user_id, emoji, created_at Recommended build order: 1. Static message list UI — Build the message list and input box with hardcoded messages. Focus on layout — message bubbles, timestamps, sender avatars. No logic yet. 2. Set up Supabase Realtime — Create the messages table and subscribe to inserts using supabase.channel(). Send a message via INSERT and watch it appear in real time. This is the core of the app. 3. Add auth and user presence — Add Clerk or Supabase Auth. Create a users table. Track online presence by updating last_seen_at every 30 seconds and showing a green dot for users active in the last 2 minutes. 4. Build DM and group rooms — Create the rooms and room_members tables. Add a room sidebar. For DMs, find or create a room with exactly the two user IDs. For groups, allow adding multiple members. 5. Read receipts and typing indicators — Track last_read_at per room_member and update it when the user scrolls to the bottom. For typing, use a Supabase Realtime broadcast channel (not database) — ephemeral, no DB writes. 6. File and image sharing — Upload files to Supabase Storage or Cloudinary. Store the URL in the message content field with a type of "image" or "file". Render images inline, files as download links. 7. Push notifications — Use Expo Notifications (mobile) or the Web Push API (browser). Store device tokens per user. Send a push when a new message arrives in a room the user is not currently viewing. Known pitfalls to avoid: - Polling instead of WebSockets — setInterval fetch every 2 seconds feels laggy and hammers your database. Use Supabase Realtime or Socket.io from day one. - Storing typing state in the database — every keypress becomes a DB write for every user in the room. Use a Realtime broadcast channel (in-memory, not persisted) for typing indicators. - Not paginating message history — loading 10,000 messages on room join will crash mobile browsers. Fetch the last 50 messages and load more as the user scrolls up. - Forgetting message ordering under concurrent inserts — sort by created_at, but add an id (ulid or snowflake) as a tiebreaker for messages sent in the same millisecond. Tech stack (intermediate): Next.js + Supabase Realtime + Clerk — self-hostable, Postgres-backed, production-ready </context> <role> You are a Senior Full-Stack Engineer and product architect who has shipped production Chat Apps before. You know exactly where developers get stuck and how to structure the project to avoid rewrites. </role> <task id="step-1-clarify"> Before writing any code or spec, ask me 3–5 clarifying questions that will meaningfully change the architecture. Focus on: scale expectations, auth requirements, platform (web / mobile / both), must-have vs nice-to-have features for the MVP, and any hard constraints (budget, deadline, existing infrastructure). <example> BAD: "What tech stack do you want to use?" — too broad, doesn't change architecture decisions. GOOD: "Do you need real-time sync across devices, or is single-device with periodic refresh acceptable? This decides whether we use WebSockets or simple REST polling and significantly affects infrastructure complexity." </example> </task> <task id="step-2-architect"> After I answer your questions, generate a complete project specification including: 1. Final tech stack with version numbers 2. Full file and folder structure 3. Complete database schema — every table, column, type, index, and foreign key 4. All API routes with request/response shapes and auth requirements 5. Component tree with TypeScript props interfaces 6. Auth and authorisation flow (who can do what) 7. Step-by-step implementation plan in the exact build order from <context> above 8. All environment variables with descriptions <self_check> Before presenting the spec, verify: □ Every answer I gave in step 1 is reflected in the spec □ The database schema matches the data model in <context> □ The implementation plan follows the build order from <context> □ No circular dependencies in the component tree □ Auth is wired up before any protected routes are built □ All known pitfalls from <context> are addressed in the spec </self_check> </task> <task id="step-2.5-agents-md"> Generate an AGENTS.md file at the project root. This file is read automatically by Claude Code, Cursor, Windsurf, Sourcegraph Cody, and all major AI coding tools at the start of every session. Include: - Project overview (2–3 sentences) - Tech stack with version numbers - Folder structure with one-line descriptions - Key architectural decisions and why they were made - Coding conventions: naming (camelCase components, kebab-case files), max 200 lines per file, one concern per file - Available commands: dev, build, test, lint, db:migrate, db:seed Note in the file: "Cursor users can symlink .cursorrules → AGENTS.md. Claude Code users can symlink CLAUDE.md → AGENTS.md." </task> <task id="step-3-implement"> Implement the full project following the spec from step 2, in the exact order defined. For each step: - Write the complete code (no placeholders or TODOs) - Confirm the step is working before moving to the next - Note any deviations from the spec with an explanation <constraints> - Max 200 lines per file. WHY: every file must fit in one AI context window for easy review and editing. - One concern per file. WHY: mixing auth logic into API routes makes it impossible to reuse — extract to lib/auth.ts. - TypeScript strict mode, no `any` types. WHY: catches data shape mismatches at compile time, not in production at 2am. - All database queries in server components or API routes only. WHY: keeps credentials server-side, prevents accidental client-side exposure. - All environment variables documented in .env.example. WHY: the next developer (or your future self) should be able to set up the project in under 5 minutes. - Comment every non-obvious decision. WHY: AI tools read your comments to understand intent — without them, the next edit will break the pattern you established. </constraints> </task>
How to use this prompt
- 1.Copy the prompt above
- 2.Open Claude, Cursor (Cmd+L), or Windsurf
- 3.Paste the prompt and send — the AI will ask 3–5 clarifying questions
- 4.Answer the questions, then it generates your full project spec
- 5.Continue in the same session to implement step by step
Common mistakes
What trips up most developers building this for the first time.
Polling instead of WebSockets — setInterval fetch every 2 seconds feels laggy and hammers your database. Use Supabase Realtime or Socket.io from day one.
Storing typing state in the database — every keypress becomes a DB write for every user in the room. Use a Realtime broadcast channel (in-memory, not persisted) for typing indicators.
Not paginating message history — loading 10,000 messages on room join will crash mobile browsers. Fetch the last 50 messages and load more as the user scrolls up.
Forgetting message ordering under concurrent inserts — sort by created_at, but add an id (ulid or snowflake) as a tiebreaker for messages sent in the same millisecond.
Recommended tech stack
Pick the level that matches your experience.
Firebase Realtime Database + React — handles WebSocket complexity automatically
Next.js + Supabase Realtime + Clerk — self-hostable, Postgres-backed, production-ready
Node.js + Socket.io + Redis pub/sub + Postgres + S3 — full control over scaling
Take it further — related ideas
Each comes with revenue math, a full build guide, and a prompt to paste into Claude or Cursor.
9 ideas in the archive
PackTrack - AI Delay Predictor That Warns E-Commerce Sellers Before a Shipment Goes Late
Small e-commerce sellers find out their shipment is late when the customer already emailed asking where their order is. PackTrack monitors supplier shipment data, carrier APIs, and historical delay patterns to predict delays 5-10 days before they happen and fires an alert so sellers can proactively message customers before the complaint. Reactive customer service is dead — this is the proactive version.
ArchiveSafe - ChatGPT Conversation Backup Before the Archive Button Destroys Your Work
You spend 3 hours in a ChatGPT thread building something brilliant, click Archive, and poof — good luck finding it ever again. ArchiveSafe is a browser extension that intercepts the Archive action and auto-exports your conversation to searchable Markdown before it disappears. Think Time Machine for your ChatGPT brain.
TokenGuard - Claude API Cost Firewall Before You Hit $2000
Claude's context window is a gift until your bill arrives and you're explaining a four-figure charge to your accountant. TokenGuard is a browser extension that wraps every Claude.ai and API call with real-time token counting, running cost display, and hard spending limits you actually control.
TimeSync - Real-Time Monday.com to Toggl and Harvest Bridge With Full Task Context
Monday.com passes 'Monday App' as the project name to every time tracking tool, making billable hours useless for client invoicing. TimeSync listens to Monday board events and auto-creates Toggl and Harvest entries with the actual task name, board, and assignee so your timesheet actually matches your work.
CallVault - MCP Server That Injects Live Sales Call Context into Claude
Your AE is on a Zoom call with a prospect while Claude sits open doing nothing useful because it has no idea who the prospect is, what they said last time, or what deal stage they are in. CallVault is an MCP server that exposes your CRM deal history, call transcripts, and prospect LinkedIn data as tools Claude can query mid-conversation.
ChatExport - One-Click Gemini Chat History Exporter to Markdown, PDF, and DOCX
Gemini has no export button and users are manually copy-pasting entire research sessions into Word and reformatting for 20 minutes. ChatExport is a Chrome extension that detects your Gemini chats and exports them clean in one click. Your AI research sessions deserve better than Ctrl+A, Ctrl+C.
LogicProbe - Natural Language SQL Error Explainer and Auto-Fix Agent
Nobody reads Postgres error messages — they are written for database internals engineers who have been awake for 72 hours and hate you. LogicProbe is an NLP agent that takes your raw SQL error, your schema context, and your original intent in plain English, then outputs a plain-English diagnosis plus a corrected query with a line-by-line diff explaining what changed and why. Data analysts and junior devs will pay for this before you finish the landing page.
RedditLense - Automated Reddit Prospect Radar with CRM Sync
Your SDRs are spending three hours per day manually scrolling Reddit looking for buying signals like 'anyone recommend a tool for X' — that is a $90/hour problem dressed up as a $15/hour task. RedditLense monitors keyword-triggered Reddit posts in real-time, scores each post for buyer intent using NLP, and pushes warm leads directly into HubSpot or a Pipedrive webhook. First five SDRs pay $99/month each before you write a single line of marketing copy.
PrivacyGuard - PII Detection Layer Before Your Prompts Hit Any LLM
Every dev team has that one paranoid colleague who refuses to paste client data into ChatGPT — turns out they are right and everyone else is wrong. PrivacyGuard sits between your team and any LLM, scans outbound prompts for PII and sensitive data in real-time, and optionally reroutes flagged prompts to a self-hosted Ollama instance. Ship this to one fintech or law-adjacent SaaS team and charge $500/month before lunch.