messageCross Icon
Cross Icon
Utilizing data

Real-Time Data Tables in Vue with PocketBase vs Supabase

Real-Time Data Tables in Vue with PocketBase vs Supabase
Real-Time Data Tables in Vue with PocketBase vs Supabase

Modern web applications need more than just a slick UI; they demand real-time updates that keep users informed without constantly refreshing the page.

In this guide, we’ll compare and implement real-time data synchronization in a Vue 3 + Vuetify project using two popular backends: PocketBase (lightweight, local-first) and Supabase (cloud-native, Postgres-based).

We’ll show how both platforms integrate into a Vue 3 project and how you can build a real-time bookings dashboard in just a few steps.

What We’re Building

A Bookings Dashboard in Vue 3 that:

  • Displays a list of current bookings
  • Updates the table in real-time when a booking is added, updated, or deleted
  • Supports expandable rows for more information

Tech Stack

  • Vue 3 with Composition API
  • Vuetify 3 for UI components
  • PocketBase or Supabase for the backend
  • Vite for project setup

Installing and Setting Up the Backend

PocketBase (Local Realtime Server)

1. Download PocketBase Binary

Go to https://pocketbase.io, download the binary for your OS (Linux/macOS/Windows).

2. Start the Server

./pocketbase serve

It runs at http://127.0.0.1:8090. Open that in your browser to access the admin UI.

3. Create the Bookings Collection

Using the admin UI:

  • Collection Name: bookings
  • Fields: customer_name, booking_date, status, notes
  • Enable real-time (default)

4. Install the PocketBase SDK

Code

npm install pocketbase
      

5. Create a reusable PocketBase client

Code

// /api/pocketbase.ts

import PocketBase from 'pocketbase';

const pb = new PocketBase('http://127.0.0.1:8090');
export default pb;
      
Hire Now!

Hire Vue.js Developers Today!

Ready to bring your web application vision to life? Start your journey with Zignuts expert Vue.js developers.

**Hire now**Hire Now**Hire Now**Hire now**Hire now

Supabase (Cloud-hosted Backend)

1. Create a Supabase Project

Go to https://app.supabase.com, sign in, and create a new project.

2. Create a Table

Under the SQL Editor or Table Editor, create a table called bookings with fields:

  • id: UUID (Primary key)
  • customer_name: Text
  • booking_date: Timestamp
  • status: Text
  • notes: Text

3. Enable Realtime on the Table

  • Go to Database > Replication
  • Enable replication for the bookings table

4. Install Supabase SDK

Code

npm install @supabase/supabase-js
      

5. Create a reusable Supabase client

Code

// /api/supabase.ts
import { createClient } from '@supabase/supabase-js';

const supabaseUrl = 'https://your-project-id.supabase.co';
const supabaseKey = 'your-anon-key'; // found in project settings
export const supabase = createClient(supabaseUrl, supabaseKey);        
      

Vue Component: Realtime Booking Table

This example works identically with both backends. First, let’s build the table component.

Vuetify Data Table with Expandable Rows

Code

<template>
  <v-data-table
    :headers="headers"
    :items="bookings"
    item-value="id"
    show-expand
    :expanded.sync="expanded"
  >
    <template #expanded-item="{ item }">
      <v-row>
        <v-col cols="12">Notes: {{ item.notes }}</v-col>
      </v-row>
    </template>
  </v-data-table>
  </template>
  <script setup>
  import { ref } from 'vue';
  const headers = [
  { title: 'Customer', key: 'customer_name' },
  { title: 'Status', key: 'status' },
  { title: 'Booking Date', key: 'booking_date' },
  ];
  const bookings = ref([]);
  const expanded = ref([]);
</script>
      

PocketBase: Add Realtime Logic

Code

// bookings-pocketbase.ts
import { onMounted, onBeforeUnmount, ref } from "vue";
import pb from "@/api/pocketbase";

const bookings = ref([]);
onMounted(async () => {
  bookings.value = await pb.collection("bookings").getFullList({ sort: "-created" });
  pb.collection("bookings").subscribe("*", (e) => {
    if (e.action === "create") {
      bookings.value.unshift(e.record);
    } else if (e.action === "update") {
      const idx = bookings.value.findIndex(b => b.id === e.record.id);
      if (idx !== -1) bookings.value[idx] = e.record;
    } else if (e.action === "delete") {
      bookings.value = bookings.value.filter(b => b.id !== e.record.id);
    }
  });
});
onBeforeUnmount(() => {
  pb.collection("bookings").unsubscribe("*");
});        
      

Supabase: Add Realtime Logic

Code

// bookings-supabase.ts
import { onMounted, onBeforeUnmount, ref } from "vue";
import { supabase } from "@/api/supabase";

const bookings = ref([]);
let channel;
onMounted(async () => {
  const { data, error } = await supabase
    .from("bookings")
    .select("*")
    .order("created_at", { ascending: false });
  bookings.value = data;
  channel = supabase
    .channel("public:bookings")
    .on("postgres_changes", { event: "*", schema: "public", table: "bookings" }, (payload) => {
      const record = payload.new || payload.old;
      if (payload.eventType === "INSERT") {
        bookings.value.unshift(payload.new);
      } else if (payload.eventType === "UPDATE") {
        const idx = bookings.value.findIndex(b => b.id === record.id);
        if (idx !== -1) bookings.value[idx] = payload.new;
      } else if (payload.eventType === "DELETE") {
        bookings.value = bookings.value.filter(b => b.id !== record.id);
      }
    })
    .subscribe();
});
onBeforeUnmount(() => {
  channel?.unsubscribe();
});
      

PocketBase vs Supabase: Comparison

PocketBase is known for its very fast setup, thanks to its local binary approach, making it ideal for quick MVPs and offline-first applications. It uses a file-based SQLite database and supports WebSocket-based real-time updates. Hosting is self-managed, and it’s designed to be desktop-friendly. While it includes basic role-based access control, it also has built-in file storage. However, scaling is manual, often requiring you to embed it directly into your app or manage infrastructure yourself.

On the other hand, Supabase is better suited for production-grade apps and team environments. It uses PostgreSQL under the hood and offers Postgres change streams for real-time features. Supabase is fully managed and cloud-hosted, which means setup requires creating a cloud project. It provides advanced role-based access with features like Row Level Security (RLS) and JWT-based authentication. Just like PocketBase, Supabase includes built-in file storage, but it shines when it comes to automatic scaling, making it a better fit for larger or growing applications. When Should You Use PocketBase?

  • You’re building an MVP, PWA, or offline-first mobile/desktop app
  • You want a quick setup with minimal dependencies
  • You prefer running the backend as a local binary or in Electron

When Should You Use Supabase?

  • You need a production-grade, scalable backend
  • You rely on Postgres features (joins, foreign keys, RLS)
  • You want robust auth, file storage, edge functions, and analytics

Final Thoughts

Both PocketBase and Supabase are excellent choices for modern Vue projects.
Your selection depends on your scaling needs, database preference, and deployment strategy.

  • For quick setups and offline-friendly apps: PocketBase
  • For full-scale web platforms: Supabase
card user img
Twitter iconLinked icon

Passionate developer with expertise in building scalable web applications and solving complex problems. Loves exploring new technologies and sharing coding insights.

Book a FREE Consultation

No strings attached, just valuable insights for your project

Valid number
Please complete the reCAPTCHA verification.
Claim My Spot!
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
download ready
Thank You
Your submission has been received.
We will be in touch and contact you soon!
View All Blogs