reflex Documentation

๏ธ Web apps in pure Python ๐Ÿ

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy reflex on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name reflex -p 443:443 --restart always reflex-dev/reflex:latest
Configured Services & Ports
โš™๏ธ app
image: build locally
โš™๏ธ webserver
image: build locally
๐Ÿ”Œ Ports: 443:443, 80:80
docker-compose.yml
yaml (docker-compose.yml)
# Base compose file production deployment of reflex app with Caddy webserver
# providing TLS termination and reverse proxying.
#
# See `compose.prod.yaml` for more robust and performant deployment option.
#
# During build and run, set environment DOMAIN pointing
# to publicly accessible domain where app will be hosted
services:
  app:
    environment:
      REFLEX_DB_URL: sqlite:///data/reflex.db
    build:
      context: .
    volumes:
      - db-data:/app/data
      - upload-data:/app/uploaded_files
    restart: always

  webserver:
    environment:
      DOMAIN: ${DOMAIN:-localhost}
    ports:
      - 443:443
      - 80:80 # For acme-challenge via HTTP.
    build:
      context: .
      dockerfile: Caddy.Dockerfile
      # Build the app image first and expose it to Caddy.Dockerfile as `app`
      # so the static frontend can be copied out of it.
      additional_contexts:
        app: service:app
    volumes:
      - caddy-data:/data
      - caddy-config:/config
    restart: always
    depends_on:
      - app

volumes:
  # SQLite data
  db-data:
  # Uploaded files
  upload-data:
  # TLS keys and certificates
  caddy-data:
  # Caddy's copy of its own config
  caddy-config:

File: README.md


[!NOTE]
Build faster with Reflex:


Introduction

Reflex is a library to build full-stack web apps in pure Python.

Key features:

  • Pure Python - Write your app's frontend and backend all in Python, no need to learn Javascript.
  • Full Flexibility - Reflex is easy to get started with, but can also scale to complex apps.

See our architecture page to learn how Reflex works under the hood.

โš™๏ธ Installation

Important: We strongly recommend using a virtual environment to ensure the reflex command is available in your PATH.

๐Ÿฅณ Create your first app

Create a project, add Reflex, and start the development server with uv:

shell
mkdir my_app_name
cd my_app_name
uv init

uv add reflex
uv run reflex init
uv run reflex run

You should see your app running at http://localhost:3000.

Now you can modify the source code in my_app_name/my_app_name.py. Reflex has fast refreshes so you can see your changes instantly when you save your code.

๐Ÿซง Example App

Build an image generation app in Python with Reflex: define the UI, manage state in a class, and call an image model from an event handler.

python
import reflex as rx
import openai

client = openai.AsyncOpenAI()


class State(rx.State):
    prompt: str = ""
    image_url: str = ""
    processing: bool = False

    @rx.event
    def set_prompt(self, value: str):
        self.prompt = value

    @rx.event
    async def generate(self):
        self.processing = True
        yield
        response = await client.images.generate(
            model="gpt-image-1.5",
            prompt=self.prompt,
        )
        self.image_url = f"data:image/png;base64,{response.data[0].b64_json}"
        self.processing = False


def index():
    return rx.vstack(
        rx.heading("Image Generator"),
        rx.input(placeholder="Enter a prompt...", on_change=State.set_prompt),
        rx.button("Generate", on_click=State.generate, loading=State.processing),
        rx.image(src=State.image_url),
    )


app = rx.App()
app.add_page(index, title="Reflex:Image Generation")

All Thanks To Our Contributors:


File: docker-example/production-one-port/README.md

production-one-port

This docker deployment runs Reflex in prod mode, exposing a single HTTP port:

  • 8080 ($PORT) - Caddy server hosting the frontend statically and proxying requests to the backend.

The deployment also runs a local Redis server to store state for each user.

Conceptually it is similar to the simple-one-port example except it:

  • has layer caching for python, reflex, and node dependencies
  • uses multi-stage build to reduce the size of the final image

Using this method may be preferable for deploying in memory constrained
environments, because it serves a static frontend export, rather than running
the Vite server via node.

Build

console
docker build -t reflex-production-one-port .

Run

console
docker run -p 8080:8080 reflex-production-one-port

Note that this container has no persistence and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.

Usage

This container should be used with an existing load balancer or reverse proxy to
terminate TLS.

It is also useful for deploying to simple app platforms, such as Render or Heroku.


File: docker-example/production-compose/README.md

production-compose

This example production deployment uses automatic TLS with Caddy serving static
files for the frontend and proxying requests to both the frontend and backend.
It is intended for use with a standalone VPS that is only hosting a single
Reflex app.

The production app container (Dockerfile), builds and exports the frontend
statically (to be served by Caddy). The resulting image only runs the backend
service.

The webserver service, based on Caddy.Dockerfile, copies the static frontend
and Caddyfile into the container to configure the reverse proxy routes that will
forward requests to the backend service. Caddy will automatically provision TLS
for localhost or the domain specified in the environment variable DOMAIN.

This type of deployment should use less memory and be more performant since
nodejs is not required at runtime.

Customize `Caddyfile` (optional)

If the app uses additional backend API routes, those should be added to the
@backend_routes path matcher to ensure they are forwarded to the backend.

Build Reflex Production Service

During build, set DOMAIN environment variable to the domain where the app will
be hosted! (Do not include http or https, it will always use https).

If DOMAIN is not provided, the service will default to localhost.

bash
DOMAIN=example.com docker compose build

This will build both the app service from the prod.Dockerfile and the webserver
service via Caddy.Dockerfile.

Run Reflex Production Service

bash
DOMAIN=example.com docker compose up

The app should be available at the specified domain via HTTPS. Certificate
provisioning will occur automatically and may take a few minutes.

Data Persistence

Named docker volumes are used to persist the app database (db-data),
uploaded_files (upload-data), and caddy TLS keys and certificates
(caddy-data).

More Robust Deployment

For a more robust deployment, consider bringing the service up with
compose.prod.yaml which includes postgres database and redis cache, allowing
the backend to run with multiple workers and service more requests.

bash
DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml up -d

Postgres uses its own named docker volume for data persistence.

Admin Tools

When needed, the services in compose.tools.yaml can be brought up, providing
graphical database administration (Adminer on http://localhost:8080) and a
redis cache browser (redis-commander on http://localhost:8081). It is not recommended
to deploy these services if they are not in active use.

bash
DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml -f compose.tools.yaml up -d

File: docker-example/production-app-platform/README.md

production-app-platform

This example deployment is intended for use with App hosting platforms, like
Azure, AWS, or Google Cloud Run.

Architecture

The production deployment consists of a few pieces:

  • Backend container - built by Dockerfile Runs the Reflex backend
    service on port 8000 and is scalable to multiple instances.
  • Redis container - A single instance the standard redis docker image should
    share private networking with the backend
  • Static frontend - HTML/CSS/JS files that are hosted via a CDN or static file
    server. This is not included in the docker image.

Deployment

These general steps do not cover the specifics of each platform, but all platforms should
support the concepts described here.

Vnet

All containers in the deployment should be hooked up to the same virtual private
network so they can access the redis service and optionally the database server.
The vnet should not be exposed to the internet, use an ingress rule to terminate
TLS at the load balancer and forward the traffic to a backend service replica.

Redis

Deploy a redis instance on the vnet.

Backend

The backend is built by the Dockerfile in this directory. When deploying the
backend, be sure to set REFLEX_REDIS_URL=redis://internal-redis-hostname to connect to
the redis service.

Ingress

Configure the load balancer for the app to forward traffic to port 8000 on the
backend service replicas. Most platforms will generate an ingress hostname
automatically. Make sure when you access the ingress endpoint on /ping that it
returns "pong", indicating that the backend is up an available.

Frontend

The frontend should be hosted on a static file server or CDN.

Important: when exporting the frontend, set the API_URL environment variable
to the ingress hostname of the backend service.

If you will host the frontend from a path other than the root, set the
REFLEX_FRONTEND_PATH environment variable appropriately when exporting the frontend.

Most static hosts will automatically use the /404.html file to handle 404
errors. This is essential for dynamic routes to work correctly. Ensure that
missing routes return the /404.html content to the user if this is not the
default behavior.

For Github Pages: ensure the file .nojekyll is present in the root of the repo
to avoid special processing of underscore-prefix directories, like _next.

Platform Notes

The following sections are currently a work in progress and may be incomplete.

Azure

In the Azure load balancer, per-message deflate is not supported. Add the following
to your rxconfig.py to workaround this issue.

python
import uvicorn.workers

import reflex as rx


class NoWSPerMessageDeflate(uvicorn.workers.UvicornH11Worker):
    CONFIG_KWARGS = {
        **uvicorn.workers.UvicornH11Worker.CONFIG_KWARGS,
        "ws_per_message_deflate": False,
    }


config = rx.Config(
    app_name="my_app",
    gunicorn_worker_class="rxconfig.NoWSPerMessageDeflate",
)

Persistent Storage

If you need to use a database or upload files, you cannot save them to the
container volume. Use Azure Files and mount it into the container at /app/uploaded_files.

Resource Types

  • Create a new vnet with 10.0.0.0/16
    • Create a new subnet for redis, database, and containers
  • Deploy redis as a Container Instances
  • Deploy database server as "Azure Database for PostgreSQL"
    • Create a new database for the app
    • Set db-url as a secret containing the db user/password connection string
  • Deploy Storage account for uploaded files
    • Enable access from the vnet and container subnet
    • Create a new file share
    • In the environment, create a new files share (get the storage key)
  • Deploy the backend as a Container App
    • Create a custom Container App Environment linked up to the same vnet as the redis container.
    • Set REFLEX_REDIS_URL and REFLEX_DB_URL environment variables
    • Add the volume from the environment
    • Add the volume mount to the container
  • Deploy the frontend as a Static Web App

File: docker-example/simple-one-port/README.md

simple-one-port

This docker deployment runs Reflex in prod mode, exposing a single HTTP port:

  • 8080 ($PORT) - Caddy server hosting the frontend statically and proxying requests to the backend.

The deployment also runs a local Redis server to store state for each user.

Using this method may be preferable for deploying in memory constrained
environments, because it serves a static frontend export, rather than running
the Vite server via node.

For platforms which only terminate TLS to a single port, this container can be
deployed instead of the simple-two-port example.

Build

console
docker build -t reflex-simple-one-port .

Run

console
docker run -p 8080:8080 reflex-simple-one-port

Note that this container has no persistence and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.

Usage

This container should be used with an existing load balancer or reverse proxy to
terminate TLS.

It is also useful for deploying to simple app platforms, such as Render or Heroku.


File: docker-example/simple-two-port/README.md

simple-two-port

This docker deployment runs Reflex in prod mode, exposing two HTTP ports:

  • 3000 - node server using optimized production build
  • 8000 - python gunicorn server hosting the Reflex backend

The deployment also runs a local Redis server to store state for each user.

Build

console
docker build -t reflex-simple-two-port .

Run

console
docker run -p 3000:3000 -p 8000:8000 reflex-simple-two-port

Note that this container has no persistence and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.

Usage

This container should be used with an existing load balancer or reverse proxy to
route traffic to the appropriate port inside the container.

For example, the following Caddyfile can be used to terminate TLS and forward
traffic to the frontend and backend from outside the container.

text
my-domain.com

encode gzip

@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
	reverse_proxy localhost:8000
}

reverse_proxy localhost:3000

File: docker-example/README.md

Reflex Docker Examples

This directory contains several examples of how to deploy Reflex apps using docker.

In all cases, ensure that your requirements.txt file is up to date and
includes the reflex package.

`simple-two-port`

The most basic production deployment exposes two HTTP ports and relies on an
existing load balancer to forward the traffic appropriately.

`simple-one-port`

This deployment exports the frontend statically and serves it via a single HTTP
port using Caddy. This is useful for platforms that only support a single port
or where running a node server in the container is undesirable.

`production-compose`

This deployment is intended for use with a standalone VPS that is only hosting a
single Reflex app. It provides the entire stack in a single compose.yaml
including a webserver, one or more backend instances, redis, and a postgres
database.

`production-app-platform`

This example deployment is intended for use with App hosting platforms, like
Azure, AWS, or Google Cloud Run. It is the backend of the deployment, which
depends on a separately hosted redis instance and static frontend deployment.