3 releases
Uses new Rust 2024
| new 0.1.2 | Dec 2, 2025 |
|---|---|
| 0.1.1 | Nov 21, 2025 |
| 0.1.0 | Nov 21, 2025 |
#47 in WebSocket
Used in supabase-client-rs
125KB
2.5K
SLoC
Supabase Realtime Rust 🦀
A Rust client for Supabase Realtime implementing the Phoenix Channels WebSocket protocol.
Note: This is an unofficial, community-maintained client. For official clients, see supabase-community.
Quick Start
use supabase_realtime_rs::{RealtimeClient, RealtimeClientOptions, ChannelEvent};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to Supabase Realtime
let client = RealtimeClient::new(
"wss://your-project.supabase.co/realtime/v1",
RealtimeClientOptions {
api_key: "your-anon-key".to_string(),
..Default::default()
},
)?;
client.connect().await?;
// Subscribe to a channel
let channel = client.channel("room:lobby", Default::default()).await;
let mut rx = channel.on(ChannelEvent::broadcast("message")).await;
channel.subscribe().await?;
// Send and receive messages
channel.send(
ChannelEvent::broadcast("message"),
serde_json::json!({"text": "Hello!"})
).await?;
// Listen for messages
tokio::spawn(async move {
while let Some(msg) = rx.recv().await {
println!("Received: {:?}", msg);
}
});
Ok(())
}
Features
Core Functionality
- ✅ WebSocket connection with automatic reconnection and exponential backoff
- ✅ Channel subscriptions for pub/sub messaging
- ✅ Broadcast messaging with HTTP fallback when disconnected
- ✅ Postgres changes - Subscribe to database INSERT/UPDATE/DELETE events
- ✅ Presence tracking - Track online users with custom metadata
- ✅ Push messages with acknowledgments (ok/error/timeout callbacks)
- ✅ Type-safe error handling throughout
Technical Features
- Async/await with Tokio
- Thread-safe shared state with
Arc<RwLock<T>> - Event routing via mpsc channels
- TLS support with
native-tls - Heartbeat mechanism with timeout detection
Installation
cargo add supabase-realtime-rs
Usage Examples
Database Changes (Postgres)
use supabase_realtime_rs::{PostgresChangesFilter, PostgresChangeEvent};
let channel = client.channel("db-changes", Default::default()).await;
// Listen for all changes to the "todos" table
let mut rx = channel.on_postgres_changes(
PostgresChangesFilter::new(PostgresChangeEvent::All, "public")
.table("todos")
).await;
channel.subscribe().await?;
tokio::spawn(async move {
while let Some(change) = rx.recv().await {
println!("Database change: {:?}", change);
}
});
Note: Requires Row Level Security (RLS) policies with SELECT permissions on the table.
Presence Tracking
use serde_json::json;
let channel = client.channel("room:lobby", Default::default()).await;
channel.subscribe().await?;
// Track your presence
channel.track(json!({
"user": "Alice",
"status": "online",
"cursor_x": 100,
"cursor_y": 200
})).await?;
// Get all present users
let users = channel.presence_list().await;
println!("Online users: {:?}", users);
// Stop tracking
channel.untrack().await?;
Push Messages with Callbacks
channel.push("custom_event", serde_json::json!({"data": "value"}))
.receive("ok", |payload| {
println!("Success: {:?}", payload);
})
.receive("error", |payload| {
eprintln!("Error: {:?}", payload);
})
.receive("timeout", |_| {
eprintln!("Request timed out");
})
.send()
.await?;
Examples
The examples/ directory contains working code for all features:
# Setup (first time only)
cp .env.example .env
# Edit .env with your Supabase credentials
# Run examples
cargo run --example test_connection # Basic WebSocket connection
cargo run --example test_channel # Channel subscriptions
cargo run --example test_send # Broadcasting messages
cargo run --example test_postgres_changes # Database event streaming
cargo run --example test_presence # Presence tracking
cargo run --example test_push # Push with acknowledgments
Real-World Demo
Check out realtime-chat-demo - a full-featured chat application built with this library, demonstrating broadcast messaging, presence tracking, and WebSocket connection management.
Production Readiness
Status: Beta (v0.1.0)
Production-ready features:
- ✅ All core Phoenix Channels protocol features
- ✅ Robust reconnection and error handling
- ✅ Comprehensive examples and documentation
- ✅ CI/CD with automated testing
Known limitations:
- ⚠️ No automatic JWT token refresh (requires manual reconnect when token expires)
- ⚠️ No postgres type transformers (values received as raw strings, manual parsing required)
- ⚠️ Limited to Phoenix Channels features (no Supabase Auth integration yet)
See Cargo.toml for dependency versions.
Why Rust?
Performance: Zero-cost abstractions, compiled binary, native async/await
Safety: Memory-safe and thread-safe by default, preventing entire classes of bugs
Use Cases:
- High-performance servers and microservices
- CLI tools and system utilities
- WebAssembly applications
- Embedded systems
- Anywhere JavaScript/Node.js is too slow or too heavy
Migrating from TypeScript
Key differences from @supabase/realtime-js:
| Concept | JavaScript | Rust |
|---|---|---|
| Callbacks | channel.on('event', (payload) => {}) |
let mut rx = channel.on(event).await |
| Error Handling | try/catch |
Result<T, E> with ? operator |
| Async | async/await (Promise-based) |
async/await (Future-based with Tokio) |
| Shared State | Direct mutation | Arc<RwLock<T>> for thread safety |
| Event Listening | Single callback per event | mpsc channels (multiple consumers possible) |
Example comparison:
// JavaScript
const channel = client.channel("room:lobby");
channel.on("broadcast", { event: "message" }, (payload) => {
console.log(payload);
});
await channel.subscribe();
// Rust
let channel = client.channel("room:lobby", Default::default()).await;
let mut rx = channel.on(ChannelEvent::broadcast("message")).await;
channel.subscribe().await?;
tokio::spawn(async move {
while let Some(payload) = rx.recv().await {
println!("{:?}", payload);
}
});
Architecture
Built on idiomatic Rust patterns:
- Connection Management - WebSocket lifecycle with automatic reconnection
- Message Routing - Routes incoming messages to appropriate channel handlers
- Channel System - Subscribe to topics, filter events, manage presence
- Infrastructure - Heartbeat, HTTP fallback, background task management
Uses Phoenix Channels protocol for compatibility with Supabase Realtime.
Development
Build & Test
# Check compilation
cargo check
# Run tests
cargo test
# Format code
cargo fmt
# Lint
cargo clippy --all-features -- -D warnings
# Generate documentation
cargo doc --open
Contributing
Contributions are welcome! Here's how to get started:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Test your changes (
cargo test && cargo clippy) - Commit (
git commit -m 'Add amazing feature') - Push (
git push origin feature/amazing-feature) - Open a Pull Request
Code style:
- Follow Rust naming conventions (snake_case, PascalCase)
- Add rustdoc comments (
///) to public APIs - Include examples in documentation
- Use
Result<T, E>for error handling, avoidunwrap()
Need help? Open an issue or discussion!
License
MIT License - see LICENSE for details
Acknowledgments
- Built on Tokio async runtime
- Implements Phoenix Channels protocol
- Ported from @supabase/realtime-js
Made with 🦀 by the Rust community
Dependencies
~9–26MB
~348K SLoC