How to Build a Live Chatting App Using Supabase

Learn how to create a live chat app using Supabase with real-time features.

How to Build a Live Chatting App Using Supabase
Real-time chat apps power everything from customer support systems to social platforms. Thanks to Supabase, an open-source Firebase alternative, you can set up authentication, a database, and real-time subscriptions without heavy backend work. In this guide, we’ll walk through how to build a live chatting app using Supabase.

Why Supabase?

Supabase is built on top of PostgreSQL and provides:

  • Authentication (email, OAuth, magic links).

  • Realtime subscriptions (powered by PostgreSQL’s replication).

  • Row Level Security (RLS) for secure access.

  • Simple REST & GraphQL APIs for fast integration.

This makes it perfect for a real-time chat app.

Step 1: Set Up Your Supabase Project

  1. Go to Supabase and create a free account.

  2. Create a new project.

  3. Grab your Project URL and anon/public API key from the Project Settings → API section. You’ll use these in your frontend.

Step 2: Create the Database Schema

Inside the Supabase SQL editor, run the following schema for messages:

-- Table for chat messages
create table messages (
  id uuid primary key default uuid_generate_v4(),
  user_id uuid references auth.users not null,
  content text not null,
  created_at timestamp with time zone default now()
);

-- Enable real-time on this table
alter publication supabase_realtime add table messages;

-- Add Row Level Security
alter table messages enable row level security;

-- Policy: allow users to insert their own messages
create policy "Users can insert their own messages"
  on messages for insert
  with check (auth.uid() = user_id);

-- Policy: allow everyone to read messages
create policy "Anyone can read messages"
  on messages for select
  using (true);

This ensures:

  • Users can only send messages under their own ID.

  • Anyone can read messages in real time.

Step 3: Set Up the Frontend

You can use React + Supabase JS SDK for the frontend.

Install dependencies:

npm install @supabase/supabase-js

Initialize Supabase:

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = "YOUR_SUPABASE_URL"
const supabaseKey = "YOUR_PUBLIC_ANON_KEY"
export const supabase = createClient(supabaseUrl, supabaseKey)

Step 4: Build Authentication

Add a simple login (email/password or magic link):

async function signIn(email) {
  const { error } = await supabase.auth.signInWithOtp({ email })
  if (error) console.error(error)
}

Users can sign in, and Supabase handles sessions automatically.

Step 5: Fetch and Display Messages

You can fetch messages with:

async function fetchMessages() {
  let { data, error } = await supabase
    .from('messages')
    .select('id, content, created_at, user_id')
    .order('created_at', { ascending: true })
  return data
}

Step 6: Subscribe to Real-Time Updates

Here’s the magic—real-time chat using Supabase’s subscription:

supabase
  .channel('chat-room')
  .on(
    'postgres_changes',
    { event: 'INSERT', schema: 'public', table: 'messages' },
    payload => {
      console.log('New message:', payload.new)
      // Update UI with new message
    }
  )
  .subscribe()

Now every new message will appear instantly for all users.

Step 7: Sending Messages

To send a message:

async function sendMessage(userId, content) {
  const { error } = await supabase.from('messages').insert([
    { user_id: userId, content }
  ])
  if (error) console.error(error)
}

Step 8: Build a Simple UI (React Example)

import { useEffect, useState } from "react"
import { supabase } from "./supabaseClient"

function ChatApp() {
  const [messages, setMessages] = useState([])
  const [newMessage, setNewMessage] = useState("")

  useEffect(() => {
    fetchMessages()

    supabase
      .channel('chat-room')
      .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, payload => {
        setMessages(prev => [...prev, payload.new])
      })
      .subscribe()
  }, [])

  async function fetchMessages() {
    const { data } = await supabase.from('messages').select('*').order('created_at')
    setMessages(data)
  }

  async function handleSend() {
    const user = (await supabase.auth.getUser()).data.user
    await supabase.from('messages').insert([{ user_id: user.id, content: newMessage }])
    setNewMessage("")
  }

  return (
    <div>
      <div className="chat-box">
        {messages.map(msg => (
          <div key={msg.id}>{msg.content}</div>
        ))}
      </div>
      <input value={newMessage} onChange={e => setNewMessage(e.target.value)} />
      <button onClick={handleSend}>Send</button>
    </div>
  )
}

export default ChatApp

Next steps you can try:

  • Add user profiles and avatars.

  • Create multiple chat rooms.

  • Add typing indicators.

  • Use Supabase Storage for image/file sharing.

Supabase makes real-time apps simple, powerful, and scalable.

Zayan O

Zayan O

Oh, look at me, creating a profile like it's going to change the world. I could write something deep and meaningful here, but let's be honest, you probably just scrolled to see if I'm interesting.