Backend Modes
Standalone (Supabase) vs Unified (Soar API): how to choose, how the mode is resolved, and what does not mix.
The template ships with two complete backends behind one set of business contracts. Which one a build is assembled against is a build-level choice made in the environment before packaging — a single install authenticates and stores data against exactly one backend, and there is no user-facing switch.
| Standalone Mode | Unified Mode | |
|---|---|---|
SOAR_BACKEND_MODE | supabase (default) | soarApi |
| Auth | Supabase Auth | Better Auth (/api/auth/*, Bearer token, Rust-native only) |
| Data | PostgREST + RLS | Soar App API (/api/app/v1/*) |
| Session storage | OS-keychain commands | Rust-private keyring namespace |
| Billing | Creem web checkout | Host-managed subscription snapshot, checkout, and portal |
| OAuth / device tokens / test push | Per Standalone docs | Not implemented — capability-driven UI hides those actions |
| Shares users/data with a web app | No | Yes — same host as a conforming Web template |
Standalone Mode is the classic single-template setup: the desktop app talks directly to your Supabase project. If you only bought the Tauri template, this is your mode and nothing about it changed.
Unified Mode points the app at a conforming Web host's
Soar App API instead. Web and desktop then share one
Better Auth user, one todos table, one profile, and one
subscription row. All Unified networking
lives in Rust: the Webview receives typed business DTOs and a sanitized
session over typed commands — never the Bearer token, Authorization header,
or presigned URLs.
Start here
Pick the mode, then follow exactly one setup guide:
Standalone: Supabase Setup
Create the Supabase project: schema, auth callback, Edge Functions, and secrets.
Unified: Soar API Setup
Connect to a conforming host: Rust config, host environment, sessions, and verification.
If you are undecided, the platform-level mode guide and Compatibility Matrix compare the two deployments product-by-product.
How the mode is resolved
SOAR_BACKEND_MODE is baked into the build as a compile-time define shared by
the Webview (shared/platform/backend-mode.ts) and the Rust side
(src-tauri/src/build_env.rs):
soarApi→ Unified Mode.supabaseor unset → Standalone Mode.- Any other value fails startup ("SOAR_BACKEND_MODE must be either supabase or soarApi") — a typo cannot silently pick a backend.
Only the mode itself is exposed to the Webview; SOAR_API_BASE_URL and
SOAR_AUTH_ORIGIN stay native-only in Rust. Webview code depends on the
business contracts and contains no backend type checks.
No silent fallback. If Unified Mode is selected but SOAR_API_BASE_URL
is missing or malformed, the Soar API path fails with a diagnosable
configuration error — the app never initializes the Supabase backend
instead. A misconfigured backend should be impossible to miss.
The two modes do not mix
Each backend is a separate identity source. A Supabase session cannot call the Soar App API, and a Better Auth session cannot read your Supabase tables — by design there is no bridging, no dual-write, and no fallback from one mode to the other:
- Auth, data, storage, and subscription always come from the same backend preset. You cannot sign in with Supabase and store todos via the Soar API.
- Users created in one mode do not exist in the other. The same email registered in both places is two unrelated accounts.
Switching a production app between modes is a data migration, not a config
flip. Flipping SOAR_BACKEND_MODE on an install base means: migrating user
accounts into the new identity source (users must re-authenticate — password
hashes don't transfer automatically), moving todos, profiles, and uploaded
files, and re-pointing billing identities to the new user IDs. Pick the mode
per deployment before launch; treat a later switch as a planned migration
project.
