For AI agents: the complete documentation index is at llms.txt. Remove the trailing slash from a page URL and append .md to read its Markdown version. For the docs home, use index.md.

Self Hosting

Use reflex deploy for the managed workflow. Follow this page when you need to self-host: run the frontend and backend on your own infrastructure, including your own cloud account, an on-premise server, or a private network behind a company VPN.

Key takeaways

  • Deploy the same Reflex project to managed hosting or infrastructure you control; configure each environment's URLs, secrets, and data services.
  • Serve the app from a single production server, or export a static frontend and run the Python backend separately.
  • For a private deployment, make both frontend and backend reachable on the intended network and configure WebSocket proxying.
  • Moving from managed hosting also requires transferring persistent data, secrets, domains, and any external service configuration.
  • You operate the servers, TLS, monitoring, backups, and updates in a self-hosted environment.

Managed vs. self-hosted

Deployment choiceManaged (reflex deploy)Self-hosted
SetupDeploy through the managed workflowProvision and configure your environment
InfrastructureReflex-managed hostingYour cloud account, private network, or on-premise servers
OperationsManaged app deployment and hosting toolsYour team manages processes, networking, updates, and backups
Best fitTeams that want managed hostingTeams that need control over infrastructure and network access
MigrationStart with a standard Reflex projectDeploy the project and migrate its configuration and data

Before you start

Clone your code to a server and install the requirements.

Production Mode

Run your app in production mode:

reflex run --env prod

Production mode compiles the app, builds an optimized static frontend, and serves it together with the backend (event websocket, /ping, /_upload) from a single server on port 3000. Pass --frontend-port or --backend-port to listen on a different port. When redis is configured, the server runs 2 * cpu_count + 1 worker processes; set GRANIAN_WORKERS to override this.

The frontend and backend can also run as separate processes, for example to serve the frontend from a CDN and scale the backend independently. The frontend-only server only serves static files, so tell it where the backend is when compiling the frontend — otherwise it assumes its own port:

reflex run --env prod --backend-only --backend-port 8000
REFLEX_API_URL=http://localhost:8000 reflex run --env prod --frontend-only --frontend-port 3000

Alternatively, put a reverse proxy in front of both processes and route the backend routes (/_event, /ping, /_upload, /_health) to the backend port, as the Caddyfiles in the container examples below do.

API URL

The frontend connects to the backend at api_url. When api_url points at localhost (the default), the frontend substitutes the hostname it was loaded from, and when the page is served over HTTPS it also drops the port and connects to its own origin. So a single-port production deployment behind a TLS-terminating proxy needs no api_url configuration at all.

Set api_url explicitly when the backend is reachable at a different address than the frontend, for example when the frontend is exported to a static host and the backend runs elsewhere:

config = rx.Config(
    app_name="your_app_name",
    api_url="https://api.example.com",
)

It is also possible to set the environment variable REFLEX_API_URL at run time or export time to retain the default for local development.

Proxying to a Subpath

If you want to serve the backend behind a reverse proxy at a subpath (e.g. nginx routing /api/* to Reflex), set backend_path on the config instead of baking the prefix into api_url. Every backend endpoint (event websocket, /ping, /_upload, /_health, /_all_routes) is mounted under that prefix, and the frontend baked into the export automatically calls the backend at the prefixed URLs — no request rewriting in the proxy is required.

config = rx.Config(
    app_name="your_app_name",
    api_url="http://app.example.com:8000",
    backend_path="/api",
)

frontend_path plays the analogous role for the frontend and the two are independent.

Note: changing backend_path (or frontend_path) requires a full restart of reflex run — routes and mount points are registered at startup, so hot reload alone will not move them.

Exporting a Static Build

Exporting a static build of the frontend allows the app to be served using a static hosting provider, such as Netlify or GitHub Pages. Make sure api_url is set to an accessible backend URL when the frontend is exported.

REFLEX_API_URL=https://api.example.com reflex export

This will create a frontend.zip file with your app's minified HTML, Javascript, and CSS build that can be uploaded to your static hosting service.

It also creates a backend.zip file with your app's backend Python code to upload to your server and run.

You can export only the frontend or backend by passing in the --frontend-only or --backend-only flags.

It is also possible to export the components without zipping. To do this, use the --no-zip parameter. This provides the frontend in the .web/build/client/ directory and the backend can be found in the root directory of the project.

The export also writes a pre-compressed .gz copy of the compressible text assets (JS, CSS, HTML, JSON, SVG, and similar), so configure the static host to serve those directly where it supports it. Set the frontend_compression_formats config option to also generate brotli or zstd copies.

Reflex Container Service

Another option is to run your Reflex service in a container. Several Dockerfiles with additional documentation are available in the Reflex project in the directory , ranging from a single container serving everything on one port to a full compose stack with a TLS-terminating webserver, redis, and postgres. The production example is the place to start.

Before building the image, add a requirements.txt to the project folder that includes reflex and commit the reflex.lock/ directory so the frontend dependencies installed in the image match the ones you developed against.

The project structure should look like this:

hello
├── assets
├── hello
│   ├── __init__.py
│   └── hello.py
├── reflex.lock
├── rxconfig.py
├── Caddyfile
├── Dockerfile
└── requirements.txt

After all changes have been made, the container image can now be created as follows.

docker build -t reflex-project:latest .

Finally, you can start your Reflex container service as follows.

docker run -d -p 8080:8080 --name app reflex-project:latest

FAQ

Can a Reflex app run entirely behind a company VPN?

Yes. Self-host both the frontend and backend on infrastructure reachable through your VPN or private network. Configure internal DNS, TLS, and WebSocket routing as needed. External APIs, authentication services, fonts, and other resources used by the app still need network access or local alternatives; self-hosting alone does not make an app air-gapped.

Can I run separate development, staging, and production environments?

Yes. Use separate deployments with per-environment configuration, secrets, database URLs, and backend addresses. A self-hosted Reflex app can run as a production server or as a static frontend with a separate Python backend.

Can I start on managed hosting and move to self-hosting later?

Yes. You can deploy the same Reflex project on your own infrastructure. Plan the transfer of persistent data, secrets, domains, and integrations, and update environment-specific configuration such as the API URL. Test the self-hosted deployment before switching traffic.