Back to Blog
SupabaseValtioReal-TimeState ManagementFinancial Apps

Integrating Supabase and Valtio for Real-Time State Management in Financial Apps

A deep dive into combining Supabase's real-time subscriptions with Valtio's proxy-based state management to build responsive, data-driven financial applications.

P

Prizmstack Team

January 15, 2026

3 min read
522 words
Integrating Supabase and Valtio for Real-Time State Management in Financial Apps

Building financial applications demands instant data updates, robust state synchronization, and a developer experience that scales with complexity. In this post, we walk through how we combine Supabase for real-time database subscriptions with Valtio for lightweight, proxy-based state management.


Why This Stack?

ConcernSupabaseValtio
Real-time dataPostgres + Realtime channels—
Client state—Proxy-based reactivity
AuthBuilt-in Row Level Security—
Bundle sizeServer-side~3 kB

Financial dashboards often display live portfolio values, transaction feeds, and alerts. Supabase's Realtime feature pushes row-level changes over WebSockets, while Valtio lets React components subscribe to only the slices of state they need—no context providers or reducers required.


Architecture Overview

Architecture overview

  1. Supabase client subscribes to a Postgres channel (e.g., transactions).
  2. On INSERT, UPDATE, or DELETE, the callback mutates the Valtio store.
  3. React components using useSnapshot re-render automatically.

Step-by-Step Implementation

1. Define the Valtio Store

// lib/stores/transactionStore.ts
import { proxy } from 'valtio';
import type { Transaction } from '@/lib/types';
 
/**
 * Proxy store for transactions.
 * Mutations here trigger React re-renders via useSnapshot.
 */
export const transactionStore = proxy<{
  transactions: Transaction[];
  isLoading: boolean;
}>({
  transactions: [],
  isLoading: true,
});

2. Subscribe to Supabase Realtime

// lib/services/subscribeTransactions.ts
import { supabase } from '@/lib/supabase/client';
import { transactionStore } from '@/lib/stores/transactionStore';
 
export function subscribeTransactions(userId: string) {
  // Initial fetch
  supabase
    .from('transactions')
    .select('*')
    .eq('user_id', userId)
    .order('created_at', { ascending: false })
    .then(({ data }) => {
      transactionStore.transactions = data ?? [];
      transactionStore.isLoading = false;
    });
 
  // Realtime subscription
  const channel = supabase
    .channel('transactions-realtime')
    .on(
      'postgres_changes',
      { event: '*', schema: 'public', table: 'transactions', filter: `user_id=eq.${userId}` },
      (payload) => {
        switch (payload.eventType) {
          case 'INSERT':
            transactionStore.transactions.unshift(payload.new as Transaction);
            break;
          case 'UPDATE':
            const idx = transactionStore.transactions.findIndex((t) => t.id === payload.new.id);
            if (idx !== -1) transactionStore.transactions[idx] = payload.new as Transaction;
            break;
          case 'DELETE':
            transactionStore.transactions = transactionStore.transactions.filter(
              (t) => t.id !== payload.old.id
            );
            break;
        }
      }
    )
    .subscribe();
 
  // Return unsubscribe function for cleanup
  return () => {
    supabase.removeChannel(channel);
  };
}

3. Consume in React

// components/TransactionFeed.tsx
'use client';
 
import { useSnapshot } from 'valtio';
import { transactionStore } from '@/lib/stores/transactionStore';
 
export function TransactionFeed() {
  const { transactions, isLoading } = useSnapshot(transactionStore);
 
  if (isLoading) return <p>Loading...</p>;
 
  return (
    <ul>
      {transactions.map((tx) => (
        <li key={tx.id}>
          {tx.description} — ${tx.amount}
        </li>
      ))}
    </ul>
  );
}

Key Takeaways

  • Decoupled data layer: Supabase handles persistence and real-time; Valtio handles UI state.
  • Minimal boilerplate: No Redux slices, no context wrappers.
  • Scalable pattern: Add more tables/channels without restructuring your state tree.

When to Use This Pattern

  • Dashboards with live metrics (finance, analytics, IoT).
  • Collaborative apps where multiple users edit the same data.
  • Any scenario where you need sub-second UI updates from a Postgres backend.

Further Reading


Have questions or want to see this pattern in action? Contact us to schedule a technical deep-dive.

Topics covered

SupabaseValtioReal-TimeState ManagementFinancial Apps
P

Written by Prizmstack Team

Full-spectrum software agency

Get an instant analysis — and 20% off

Paste your website. We quote three solutions that add value. No email to start.

Talk to the founder.

Bryan Gaurano

Bryan Gaurano

Founder & Client Partner

I'm your client partner. My job is making sure the team does great work and your product succeeds — because that's the only way I do. Every client I've kept for years started small, and the reason they stayed is that the work was good enough they never thought about leaving.

Book a 30-min call with Bryan

Or get three priced options from your URL.

Integrating Supabase and Valtio for Real-Time State Management in Financial Apps | Prizmstack