supabase_rs
An unofficial, lightweight Rust SDK for interacting with the Supabase REST and GraphQL APIs. This SDK provides a clean, chainable query-builder interface with comprehensive CRUD operations, advanced filtering capabilities, and optional modules for Storage and Realtime functionality.
๐ Key Features
- Pure REST API by default with optional nightly GraphQL support
- Fluent Query Builder for intuitive filtering, ordering, limiting, and text search
- Complete CRUD Operations with Insert, Update, Upsert, and Delete helpers
- Type-Safe Operations with Rust's strong type system
- Connection Pooling built-in with
reqwest::Client
- Feature-Flagged Modules for Storage and Realtime (opt-in)
- Comprehensive Error Handling with detailed error types
- Async/Await Support throughout the entire API
- Clone-Friendly Client for multi-threaded applications
๐ Table of Contents
- Installation
- Features and Flags
- Quickstart
- Database Operations
- Storage Operations
- GraphQL Support
- Performance & Best Practices
- Testing
- Troubleshooting
- Migration Guide
- Contributing
- Contributors
๐ฆ Installation
Add the crate to your project using Cargo:
[]
= "0.4.14"
# With optional features
= { = "0.4.14", = ["storage", "rustls"] }
Feature Combinations
# Basic REST API only (default)
= "0.4.14"
# With Storage support
= { = "0.4.14", = ["storage"] }
# With rustls instead of OpenSSL (recommended for cross-platform)
= { = "0.4.14", = ["rustls"] }
# With experimental GraphQL support (nightly)
= { = "0.4.14", = ["nightly"] }
# All features enabled
= { = "0.4.14", = ["storage", "rustls", "nightly"] }
Environment Setup
Create a .env
file in your project root:
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your-anon-or-service-role-key
# Optional: Disable nightly warning messages
SUPABASE_RS_NO_NIGHTLY_MSG=true
# Optional: Use alternative endpoint format
SUPABASE_RS_DONT_REST_V1_URL=false
๐ก Tip: Use your service role key for server-side applications and anon key for client-side applications with Row Level Security (RLS) enabled.
๐ฏ Features and Flags
Core Features
Feature | Description | Stability | Use Case |
---|---|---|---|
Default | REST API operations with native TLS | โ Stable | Production applications |
storage |
File upload/download operations | โ Stable | Applications with file management |
rustls |
Use rustls instead of OpenSSL | โ Stable | Cross-platform deployments, Alpine Linux |
nightly |
Experimental GraphQL support | โ ๏ธ Experimental | Advanced querying, development |
Feature Flag Details
storage
: Enables the Storage module for file operations with Supabase Storage bucketsrustls
: Replaces OpenSSL with rustls for TLS connections (recommended for Docker/Alpine)nightly
: Unlocks GraphQL query capabilities (experimental, may have breaking changes)
Nightly Feature Configuration
The nightly feature shows warning messages by default. To disable them:
SUPABASE_RS_NO_NIGHTLY_MSG=true
โ ๏ธ Warning: Nightly features are experimental and may introduce breaking changes without notice. Use with caution in production environments.
๐ Quickstart
Basic Client Setup
use SupabaseClient;
use dotenv;
async
Helper Function for Reusable Client
use SupabaseClient;
/// Creates a configured Supabase client instance
///
/// # Panics
/// Panics if SUPABASE_URL or SUPABASE_KEY environment variables are not set
Multi-threaded Usage
use SupabaseClient;
use Arc;
use task;
async
๐๏ธ Database Operations
Basic CRUD
Insert Operations
use json;
use SupabaseClient;
let client = create_client;
// Basic insert - returns the new row's ID
let id = client.insert.await?;
println!;
Insert with Unique Constraint Checking
// Insert only if the record doesn't already exist
// Checks all provided fields for uniqueness
let id = client.insert_if_unique.await?;
// Returns error if a user with this email OR username already exists
Bulk Insert Operations
use Serialize;
let pets = vec!;
// Insert multiple records in a single request
client.bulk_insert.await?;
Update Operations
// Update by ID (default)
client.update.await?;
// Update by custom column
client.update_with_column_name.await?;
Upsert Operations
// Insert or update if exists
client.upsert.await?;
// Upsert without predefined ID (uses Supabase's conflict resolution)
client.upsert_without_defined_key.await?;
Delete Operations
// Delete by ID
client.delete.await?;
// Delete by custom column
client.delete_without_defined_key.await?;
Advanced Querying
Complex Filtering
use Value;
let client = create_client;
// Multiple filters with chaining
let adult_pets: = client
.select
.gte // Age >= 2
.neq // Breed != "unknown"
.text_search // Full-text search
.limit
.order // Newest first
.execute
.await?;
Column Selection and Pagination
// Select specific columns with pagination
let users: = client
.from
.columns
.range // Get first 50 records (0-49 inclusive)
.order // Oldest first
.execute
.await?;
// Using offset-based pagination
let page_2: = client
.from
.columns
.limit
.offset // Skip first 25 records
.execute
.await?;
Advanced Filter Operations
// IN operator for multiple values
let specific_breeds: = client
.select
.in_
.execute
.await?;
// Null checking
let pets_without_age: = client
.select
.eq
.execute
.await?;
Bulk Operations
Batch Processing
use try_join_all;
// Process multiple operations concurrently
let client = create_client;
let operations = vec!;
let results = try_join_all.await?;
println!;
Error Handling
Comprehensive Error Management
use json;
match client.insert.await
Retry Logic Example
use ;
async
Count Operations
โ ๏ธ Performance Note: Count operations are expensive and can be slow on large tables. Use sparingly and consider caching results.
// Count all records (expensive)
let total_users = client
.select
.count
.execute
.await?;
// Count with filters (more efficient)
let active_users = client
.select
.eq
.count
.execute
.await?;
๐ Storage Operations
๐ Requirement: Enable the
storage
feature in yourCargo.toml
The Storage module provides comprehensive file management capabilities for Supabase Storage buckets.
File Download Operations
use SupabaseStorage;
// Initialize storage client
let storage = SupabaseStorage ;
// Download file to memory
let file_bytes = storage.download.await?;
println!;
// Download file directly to disk
storage.save.await?;
Advanced Storage Patterns
// Batch download multiple files
let files = vec!;
let mut downloads = Vec new;
for filename in files
let results = try_join_all.await?;
๐ GraphQL Support
โ ๏ธ Experimental: Enable the
nightly
feature for GraphQL support. This is experimental and not production-ready.
GraphQL and REST operations can be mixed using the same client instance.
Basic GraphQL Query
use ;
use json;
let client = create_client;
let graphql_request = new;
let response = graphql_request.send.await?;
println!;
GraphQL with Variables
let query_with_variables = new;
Mixing REST and GraphQL
// Use REST for simple operations
let new_user_id = client.insert.await?;
// Use GraphQL for complex relational queries
let user_with_posts = new.send.await?;
โก Performance & Best Practices
Client Management
// โ
Good: Reuse client instances (they're cheap to clone)
let client = create_client;
let client_clone = client.clone; // Shares connection pool
// โ Avoid: Creating new clients repeatedly
// let client1 = SupabaseClient::new(...)?; // Don't do this in loops
Query Optimization
// โ
Good: Use specific column selection
let users = client
.from
.columns // Only fetch needed columns
.limit // Always use reasonable limits
.execute
.await?;
// โ
Good: Use range for pagination (more efficient than offset)
let page = client
.from
.range // Get 100 records
.execute
.await?;
// โ ๏ธ Use sparingly: Count operations are expensive
let count = client.select.count.execute.await?;
Batch Operations
// โ
Good: Use bulk_insert for multiple records
client.bulk_insert.await?;
// โ Avoid: Individual inserts in loops
// for item in items {
// client.insert("table", item).await?; // Inefficient
// }
Connection Pool Configuration
// For high-throughput applications, consider custom reqwest client
use ClientBuilder;
use Duration;
let http_client = new
.pool_max_idle_per_host
.timeout
.build?;
// Note: Custom client configuration requires modifying SupabaseClient::new()
๐งช Testing
This repository includes comprehensive test coverage with both integration and unit tests.
Test Categories
- Integration Tests: Test against live Supabase instances
- Unit Tests: Test individual components in isolation
- Performance Tests: Benchmark query performance
Running Tests
# Run all tests (requires SUPABASE_URL and SUPABASE_KEY)
# Run only unit tests (no network required)
# Run specific test module
# Run tests with output
# Run tests in release mode (faster)
Test Environment Setup
Create a .env.test
file for testing:
SUPABASE_URL=https://your-test-project.supabase.co
SUPABASE_KEY=your-test-key
SUPABASE_RS_NO_NIGHTLY_MSG=true
Writing Custom Tests
use SupabaseClient;
use json;
async
๐ง Troubleshooting
Common Issues and Solutions
Authentication Errors
Error: 401 Unauthorized
Solutions:
- Verify your
SUPABASE_URL
andSUPABASE_KEY
are correct - Ensure you're using the right key type (anon vs service role)
- Check if your API key has expired
Permission Errors
Error: 403 Forbidden
Solutions:
- Review your Row Level Security (RLS) policies
- Ensure your API key has sufficient permissions
- Check if the table/operation requires service role key
Connection Issues
Error: Connection timeout / Network error
Solutions:
- Check your internet connection
- Verify the Supabase URL is accessible
- Consider increasing timeout values
- Check if you're behind a corporate firewall
Duplicate Entry Errors
Error 409: Duplicate entry
Solutions:
- Use
insert_if_unique()
instead ofinsert()
- Check your unique constraints
- Handle duplicates gracefully in your application logic
Performance Issues
Slow Queries
Symptoms:
- Queries taking longer than expected
- High memory usage
Solutions:
// Use column selection to reduce data transfer
let users = client
.from
.columns // Only fetch needed columns
.limit // Always limit results
.execute
.await?;
// Use pagination instead of fetching all records
let page = client
.from
.range // Get 1000 records at a time
.execute
.await?;
Memory Usage
High memory consumption solutions:
- Use streaming for large datasets
- Implement pagination
- Process data in batches
- Use specific column selection
Debugging
Enable Debug Logging
// Add to your Cargo.toml
env_logger = "0.10"
// In your main function
init;
Nightly Feature Debugging
# Enable detailed endpoint logging
SUPABASE_RS_NO_NIGHTLY_MSG=false
๐ Migration Guide
From v0.3.x to v0.4.x
Breaking Changes
- Method Signatures: Some methods now return
Result<T, String>
instead ofResult<T, Error>
- Client Creation:
new()
method now returnsResult<SupabaseClient, ErrorTypes>
Migration Steps
// Old (v0.3.x)
let client = new; // Could panic
// New (v0.4.x)
let client = new?; // Returns Result
From v0.2.x to v0.3.x
Query Builder Changes
// Old
client.select.filter
// New
client.select.eq
๐ค Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
-
Clone the repository
-
Set up environment
# Edit .env with your Supabase credentials
-
Run tests
-
Check formatting and linting
Contribution Guidelines
- Code Style: Follow Rust standard formatting (
cargo fmt
) - Documentation: Add comprehensive docs for all public APIs
- Testing: Include tests for new functionality
- Performance: Consider performance implications of changes
- Compatibility: Maintain backward compatibility when possible
Areas for Contribution
- ๐ง Core Features: Improve existing CRUD operations
- ๐ฆ Storage: Enhance file upload capabilities
- ๐ GraphQL: Stabilize GraphQL support
- ๐ Documentation: Improve examples and guides
- ๐งช Testing: Add more comprehensive test coverage
- ๐ Performance: Optimize query building and execution
๐ฅ Contributors
Special thanks to all contributors who have helped improve this project:
- Hadi โ Improved & fixed the schema-to-type generator
- Izyuumi โ Improved row ID routing with updating methods
- koya1616 โ README fixes and documentation improvements
- strykejern โ Refactoring & warning fixes
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.