Environment Variables

The four env scopes — frontend-public, Rust runtime, build secrets, and Edge secrets — and every key the template reads.

A desktop app has more than one environment boundary. This template has four, and knowing which is which is the difference between a value that is safe to ship in the app and one that leaks a secret.

The four scopes

ScopePrefix / whereBundled into the app?
FrontendVITE_* in .envYes — inlined into the webview bundle. Public by design.
Rust runtimeSENTRY_DSN, SENTRY_ENVIRONMENT, UPDATE_SERVER_URLNo — read by the Rust process at runtime (or baked at compile time).
Build / CI secretsTAURI_SIGNING_*, APPLE_*, WINDOWS_CERTIFICATE*No — supplied to release builds only; no-op when unset.
Edge secretsCREEM_*, BILLING_SUCCESS_URLNo — set with supabase secrets set; never in the app .env.

The Supabase URL and publishable key are safe to ship because Row Level Security enforces authorization server-side. A Supabase service-role key is not safe and must never appear in .env. The minisign private key never enters the repo — only the public key lives in tauri.conf.json.

All frontend config is read once in shared/config.ts; see .env.example for the annotated source of truth. Every VITE_* key below already ships in .env.example.

Frontend reference (VITE_*)

Feature flags

Prop

Type

Supabase

Prop

Type

Creem product IDs

Prop

Type

Product IDs are not secrets. shared/price-config.ts maps them to plan tiers; an unset or unknown ID falls back to free, so an unconfigured build never wrongly unlocks paid features.

Observability, analytics, and support

Prop

Type

Rust runtime env

Read by the Rust process, not bundled into the webview. Each is read via std::env::var at runtime, falling back to option_env! (baked at compile time), so you can supply them either way.

Prop

Type

Update endpoint precedence (src-tauri/src/commands/update.rs): a non-empty runtime UPDATE_SERVER_URL wins; otherwise the compile-time option_env! value; otherwise the built-in default https://updates.soarstarter.com. Separately, tauri.conf.json hardcodes an endpoints entry and the minisign public key — rebrand both to point at your own feed. See Auto-Update.

Build stamps

The About-page diagnostics show a build time and commit SHA read via option_env!("VITE_BUILD_TIME") and option_env!("VITE_COMMIT_SHA") at Rust compile time. They are not in .env.example and the shipped CI does not inject them, so they default to "dev". Set them in your release build environment if you want real stamps.

Build / CI secrets

Every signing input is env-driven and no-ops when unset, so forks and local builds keep working without secrets.

Prop

Type

Edge secrets

Set with supabase secrets set; read by functions under supabase/functions/. They are reference-only in .env.example (commented out) — never put real values in the app .env.

Prop

Type

Safe-to-ship checklist

ValueSafe in app bundle?Why
Supabase URLYesIdentifies the project endpoint.
Supabase publishable keyYesIntended for clients; RLS decides which rows the user can read.
Creem product IDsYesIdentifiers only; they do not create checkout sessions by themselves.
Sentry DSNYes, with opt-inA DSN is an ingest address, not a signing secret; user opt-in still gates reporting.
Analytics write keyTreat as publicIt ships to the webview if set.
Supabase service-role keyNoBypasses RLS. Server-side only.
Creem API key / webhook secretNoServer credentials; Edge secrets only.
minisign private keyNoSigns your updates; only the public key ships (in tauri.conf.json).
Code-signing certificatesNoRelease secrets for CI or your signing machine.

On this page