flexprice-front) yourself and pointing it at that backend.
Self-hosting options
Docker Compose
Manual build
npm run build and serve them with nginx or any static host.Vercel
vercel.json.Self-hosted environment configuration
Before you build or deploy anything, set these. They’re the three variables that actually change how the app behaves in a self-hosted setup, and getting them wrong is the single most common way this deployment breaks:| Variable | Self-hosted value | Why |
|---|---|---|
VITE_APP_ENV | self-hosted | Switches the dashboard’s auth flow to call your backend’s own /auth/login and /auth/signup endpoints directly, and stores the session token in the browser instead of using Supabase. Without this, the app expects a Supabase project to exist. |
VITE_AUTH_PROVIDER | flexprice | Confirms the dashboard is using Flexprice’s own auth rather than Supabase, and hides Supabase-only UI (Google sign-in, cloud announcement banners) that don’t apply to a self-hosted instance. |
VITE_API_URL | http://<your-backend-host>:8080/v1 | Points the dashboard at your self-hosted API. See Connecting to the backend for what “reachable” means here. |
VITE_APP_ENV=self-hosted set, you do not need to fill in VITE_SUPABASE_URL or VITE_SUPABASE_ANON_KEY — leave them blank.
Full environment variable reference
Core (required)
Core (required)
| Variable | Self-hosted value | Notes |
|---|---|---|
VITE_APP_ENV | self-hosted | See above. Also accepts local, development, production for other setups. |
VITE_API_URL | Your backend’s API URL, e.g. http://localhost:8080/v1 | Must be reachable from the browser, not just the server. |
VITE_AUTH_ENABLED | true | Set this regardless; the dashboard always requires login. Kept for forward compatibility. |
VITE_AUTH_PROVIDER | flexprice | Use Flexprice’s built-in auth instead of Supabase. |
Supabase auth (leave unset for self-hosted)
Supabase auth (leave unset for self-hosted)
| Variable | Self-hosted value | Notes |
|---|---|---|
VITE_SUPABASE_URL | Leave blank | Only used when VITE_AUTH_PROVIDER=supabase. |
VITE_SUPABASE_ANON_KEY | Leave blank | Same as above. |
Observability and analytics (optional)
Observability and analytics (optional)
| Variable | Recommended for self-hosted | Notes |
|---|---|---|
VITE_SENTRY_ENABLED | false unless you run your own Sentry | Set VITE_SENTRY_DSN if enabled. |
VITE_POSTHOG_ENABLED | false unless you run your own PostHog | Set VITE_POSTHOG_KEY / VITE_POSTHOG_HOST if enabled. |
VITE_REO_ENABLED | false | Cloud session-replay integration; not relevant for self-hosted. |
Billing and support widgets (cloud-only, leave disabled)
Billing and support widgets (cloud-only, leave disabled)
| Variable | Self-hosted value | Notes |
|---|---|---|
VITE_PADDLE_ENABLED | false | Paddle checkout is used by Flexprice Cloud billing, not applicable when you self-host. |
VITE_INTERCOM_ENABLED | false | Flexprice Cloud support widget. |
Webhooks portal
Webhooks portal
| Variable | Self-hosted value | Notes |
|---|---|---|
VITE_WEBHOOK_PROVIDER | flexprice | Uses the custom Flexprice webhook portal instead of hosted Svix. Set to svix only if you’re self-hosting Svix yourself. |
VITE_SVIX_URL | Public origin of your self-hosted Svix API, or leave blank | Only needed if you run Svix yourself and set VITE_WEBHOOK_PROVIDER=svix. |
Multi-region and multi-tenant cloud features (leave unset)
Multi-region and multi-tenant cloud features (leave unset)
| Variable | Self-hosted value | Notes |
|---|---|---|
VITE_DASHBOARD_URL_INDIA / VITE_DASHBOARD_URL_US | Leave blank | Used to route between Flexprice Cloud regions; not applicable to a single self-hosted instance. |
VITE_DATA_REGION_SELECTION_ENABLED | false | Same as above. |
VITE_RESTRICTED_ENVS | Leave blank | Used by Flexprice Cloud to suspend tenant environments. |
VITE_TENANT_FEATURE_ALLOWLIST | Leave blank | Gates cloud-only UI for specific tenants; irrelevant when you’re the only tenant. |
Integrations and branding (optional)
Integrations and branding (optional)
| Variable | Notes |
|---|---|
VITE_GOOGLE_SHEETS_WEB_APP_URL | Only needed if you use the Google Sheets export integration. |
VITE_FONT_CONFIG | Optional JSON override for dashboard typography, e.g. {"primary":"Inter","fallback":"ui-sans-serif, system-ui, sans-serif"}. Omit to use the default font. |
First login: create your account
A self-hosted instance starts with no dashboard users. There’s no default username or password: every account, including your first one, is created through Sign Up against your own backend:Open the dashboard
http://localhost:3000).Use Sign Up, not Login
VITE_API_URL or backend CORS, not the auth flow itself. See Troubleshooting.Docker Compose
Prerequisites
Quick start
.env with at least the three variables from self-hosted environment configuration above, then build and start the container:
docker-compose.yml in the repo builds the image from the included Dockerfile (a multi-stage Node 20 build) and exposes the dashboard on port 3000 with a built-in healthcheck.
http://localhost:3000 once the container reports healthy, then follow First login to create your account.
Manual build and serve
If you’d rather not use Docker, build static files and serve them yourself.dist/ folder. Serve it with any of the following:
- nginx
- Vite preview server
- serve
nginx.conf (SPA fallback already configured) and point it at dist/:Deploying on Vercel
The repo includes avercel.json with the SPA rewrite already configured (/(.*) → /), so you can deploy directly:
- Import the
flexprice-frontrepository into Vercel. - Set the environment variables from the reference above in the Vercel project settings (
VITE_APP_ENV=self-hosted,VITE_AUTH_PROVIDER=flexprice,VITE_API_URL, and any optional ones you need). - Deploy. Vercel runs
npm run buildautomatically and serves thedist/output.
VITE_API_URL) since Vercel doesn’t proxy to a private network by default.Connecting to the backend
VITE_API_URLis baked into the JavaScript bundle and fetched by the end user’s browser, not by the Docker container or server that built it. Use an address the browser can actually reach: the host machine’s real IP or domain, not a Docker-internal hostname.http://localhost:8080/v1only works if the person opening the dashboard is on the same machine as the backend.- CORS: the Flexprice API needs to allow requests from the origin the dashboard is served on. If you’re serving the frontend from a different domain or port than the API expects, configure the backend’s CORS allow-list accordingly (see the backend self-hosting guide and configuration reference).
- Login and signup (
/auth/login,/auth/signup) are public endpoints: they don’t require an API key. After you log in, the dashboard authenticates every other request with the session token from that login, not with a Flexprice API key. You only need an API key (e.g. for testing withcurl) if you’re calling the API directly, outside the dashboard.
Troubleshooting
Login redirects to Supabase or shows a Supabase error
Login redirects to Supabase or shows a Supabase error
VITE_APP_ENV is not set to self-hosted, or VITE_AUTH_PROVIDER is still supabase (the .env.example default). Set both explicitly and rebuild, since Vite environment variables are baked in at build time, not read at container start.Signed up successfully but nothing happens, or Sign Up isn't in self-hosted mode
Signed up successfully but nothing happens, or Sign Up isn't in self-hosted mode
VITE_APP_ENV=self-hosted was set at build time. If it wasn’t, sign-up falls back to the Supabase flow and waits for an email confirmation that will never arrive on a self-hosted instance with no email provider configured.Blank page or 404 on refresh for routes like /customers/123
Blank page or 404 on refresh for routes like /customers/123
index.html for unknown paths. Use the bundled nginx.conf, or add an equivalent SPA fallback rule to your own server config.Dashboard loads but all API calls fail (network error or CORS)
Dashboard loads but all API calls fail (network error or CORS)
- Confirm
VITE_API_URLis reachable from your browser, not just from the container network:
- Check the browser console for a CORS error. If present, add the frontend’s origin to the backend’s CORS configuration.
- Remember Vite bakes
VITE_*variables in at build time. Changing.envafternpm run buildrequires rebuilding.
Changed .env but nothing changed in the running app
Changed .env but nothing changed in the running app
docker compose up -d --build) or rerun npm run build, then restart the container or server.Docker container unhealthy
Docker container unhealthy
http://localhost:3000 inside the container; a non-2xx response usually means the build failed or the app crashed on start. Check the logs above for the actual error.Need help?
- Check our GitHub Issues for similar problems
- Join our Slack community for real-time support
- Contact us at support@flexprice.io

