The native desktop client for Supabase.
Manage your database, auth, storage, edge functions, and more — without a browser.
Supactl is a native desktop application for Supabase — the open source Firebase alternative built on Postgres. It brings the full Supabase experience to the desktop: faster, native, offline-capable, and better designed.
Elevator pitch: "Supabase Studio, but native."
| Layer | Technology | Notes |
|---|---|---|
| Desktop shell | Tauri v2 | Rust backend, minimal Rust needed |
| Frontend | React 19 + TypeScript | Strict mode, no any types |
| Styling | Tailwind CSS v3 | Dark theme only ("Digital Obsidian") |
| Fonts | Geist Sans + Geist Mono | Via Google Fonts CDN |
| Icons | Material Symbols Outlined | Google icon font |
| DB / Auth / Storage | @supabase/supabase-js | Full Supabase SDK |
| Management API | Supabase REST API | Project listing, API keys |
| Local storage | Tauri Store Plugin | Encrypted credential storage |
| State management | Zustand | Lightweight, zero boilerplate |
| Routing | React Router v7 | Client-side navigation |
| SQL editor | CodeMirror 6 | SQL language support + custom theme |
| Package manager | pnpm | Fast, disk-efficient |
Supactl follows a bespoke dark-mode design system designed in Google Stitch. Every decision is intentional.
For the full color palette, typography guidelines, and design principles, see the DESIGN_SYSTEM.md file.
The single accent element across the app is a subtle primary green inner/outer glow applied to key CTAs and connection signals.
box-shadow: 0 0 8px rgba(62, 207, 142, 0.4);| Screen | Route | Description |
|---|---|---|
| Onboarding | /connect |
3-step flow: Welcome → Connect Project → Success |
| Table Editor | /tables/:tableName |
Spreadsheet view with schema browser + info panel |
| SQL Editor | /sql |
CodeMirror editor + tabbed queries + results table |
| Auth Users | /auth |
User management with provider badges + stats |
| Project Keys | /settings/keys |
API keys, URLs, JWT settings, system health |
| Screen | Route | Description |
|---|---|---|
| Storage Browser | /storage |
Bucket list + file grid/list + detail panel |
| RLS Policies | /rls |
Policy cards + creation form per table |
| Edge Function Logs | /logs |
Dense log stream + function stats + sparkline |
| Realtime Listener | /realtime |
Live event monitor + subscription manager |
| Migrations Tracker | /migrations |
Timeline view + SQL diff viewer |
- Cron jobs viewer
- Database queues
- Webhooks manager
- Index advisor
- Vault secrets manager
- AI SQL assistant (⌘K)
- ERD visual schema viewer
- Multi-project workspaces
supactl/
├── src/ # React frontend
│ ├── main.tsx # Entry point
│ ├── App.tsx # Router setup + AppLayout shell
│ ├── components/
│ │ ├── shell/
│ │ │ ├── TopNav.tsx # Fixed top navigation bar (40px)
│ │ │ ├── Sidebar.tsx # Fixed left sidebar (220px)
│ │ │ └── StatusBar.tsx # Fixed bottom status bar (24px)
│ │ ├── ui/ # Reusable UI primitives (planned)
│ │ └── shared/ # Shared composite components (planned)
│ ├── pages/
│ │ ├── Onboarding.tsx # 3-step connect flow
│ │ ├── TableEditor.tsx # Spreadsheet table view
│ │ ├── SqlEditor.tsx # SQL editor + results
│ │ ├── AuthUsers.tsx # Auth user management
│ │ ├── ProjectKeys.tsx # API keys / settings
│ │ ├── StorageBrowser.tsx # File/bucket manager
│ │ ├── RlsPolicyEditor.tsx # RLS policy manager
│ │ ├── EdgeFunctionLogs.tsx # Edge function log viewer
│ │ ├── RealtimeListener.tsx # Live event monitor
│ │ └── MigrationsTracker.tsx # Migration history + diff
│ ├── store/
│ │ ├── projectStore.ts # Active project, connection state
│ │ ├── schemaStore.ts # Cached schema/tables
│ │ └── uiStore.ts # Command palette, sidebar state
│ ├── lib/
│ │ ├── supabase.ts # Supabase client factory
│ │ └── storage.ts # Tauri local credential storage
│ └── styles/
│ └── globals.css # Tailwind base + scrollbar hide
├── src-tauri/ # Tauri Rust backend
│ ├── tauri.conf.json # App config (1280x800, no decorations)
│ ├── Cargo.toml # Rust deps: store, opener, window-state
│ └── src/
│ ├── main.rs # Binary entry point
│ └── lib.rs # Plugin registration (minimal)
├── tailwind.config.ts # Design system tokens
├── vite.config.ts # Vite dev server config
├── tsconfig.json # TypeScript strict config
├── package.json # Dependencies + scripts
└── contex.md # Design & architecture Bible
- Node.js ≥ 18
- pnpm ≥ 8
- Rust (via rustup)
- Visual Studio Build Tools (Windows) or Xcode CLI (macOS)
git clone <repo-url>
cd supactl
pnpm install# Frontend only (browser preview)
pnpm run dev
# Full Tauri desktop app
pnpm run tauri devpnpm run tauri buildThe compiled binary will be in src-tauri/target/release/.
{
"app": {
"windows": [{
"title": "Supactl",
"width": 1280,
"height": 800,
"minWidth": 900,
"minHeight": 600,
"decorations": false,
"transparent": false
}]
}
}decorations: false— Custom title bar with macOS-style traffic light buttons- Window state persistence — Remembers size/position between sessions via
tauri-plugin-window-state - Credential storage — Encrypted local storage via
tauri-plugin-store
User opens app
→ Check Tauri store for saved credentials
→ If none: redirect to /connect (Onboarding)
→ If found: create Supabase client → test connection
→ Success: load schema → redirect to /tables
→ Fail: show disconnected state + retry
Supabase client:
createClient(projectUrl, serviceRoleKey)
— service role key used for desktop admin (bypasses RLS)
All DB queries:
supabase.from(table).select() / .insert() / .update() / .delete()
OR raw SQL via supabase.rpc()
Credential storage:
Tauri store plugin → { projectUrl, serviceRoleKey }
Never sent anywhere — stays on device
Three Zustand stores manage all application state:
| Store | Purpose | Key Fields |
|---|---|---|
projectStore |
Connection & credentials | projectUrl, serviceKey, isConnected, isConnecting |
schemaStore |
Cached database schema | tables[], isLoading |
uiStore |
UI toggles | commandPaletteOpen, sidebarCollapsed |
| Package | Version | Purpose |
|---|---|---|
@supabase/supabase-js |
^2.101.0 | Supabase SDK |
zustand |
^5.0.12 | State management |
react-router-dom |
^7.13.2 | Client-side routing |
@uiw/react-codemirror |
^4.25.9 | CodeMirror React wrapper |
@codemirror/lang-sql |
^6.10.0 | SQL syntax support |
@tauri-apps/plugin-store |
^2.4.2 | Encrypted local storage |
@tauri-apps/plugin-window-state |
~2.4.1 | Window position persistence |
| Phase | Status | Completion |
|---|---|---|
| Phase 0 — Project Setup | 🟡 In Progress | ~70% |
| Phase 1 — Shell + Onboarding | 🟡 In Progress | ~50% |
| Phase 2 — Core Screens | 🟢 Mostly Done | ~85% |
| Phase 3 — Advanced Screens | 🟢 Mostly Done | ~85% |
| Phase 4 — Polish | 🔴 Not Started | ~10% |
- ✅ Full Tauri v2 desktop shell with custom title bar
- ✅ All 10 screens rendered with correct layouts
- ✅ Onboarding flow (connect → test → save credentials)
- ✅ Real Supabase data fetching (tables, auth users, storage)
- ✅ SQL editor with CodeMirror, multi-tab support
- ✅ Realtime event simulation with live counters
- ✅ RLS policy editor with command-colored cards
- ✅ Migration timeline with diff viewer
- ✅ TypeScript compiles with 0 errors
- 🔴 Reusable UI component library (Button, Badge, Input, Card, etc.)
- 🔴 Command Palette (⌘K)
- 🔴 Custom hooks (useConnection, useSchema, useProject)
- 🔴 Management API integration
- 🔴 Custom CodeMirror theme matching design system
- 🔴 Disconnected state UI (red banner, dimmed content)
- 🔴 Global keyboard shortcuts
- 🔴 Empty states on all screens
- Components: PascalCase (
TableEditor.tsx) - Hooks: camelCase with
useprefix (useSchema.ts) - Stores: camelCase with
Storesuffix (projectStore.ts) - CSS: Tailwind utility classes only (no custom CSS except
globals.css) - Constants: Centralized in
lib/constants.ts - Types: No
any— proper TypeScript interfaces for all props
- Service role key stored locally via Tauri's encrypted store plugin
- Credentials never logged, transmitted, or exposed to the renderer process URL
persistSession: falseprevents auth token leakageuser-select: nonefor desktop-native feel (text selection enabled in inputs)
Designed by Athul Nair M