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.

Base Vars

Vars are any fields in your app that may change over time. A Var is directly rendered into the frontend of the app.

Base vars are defined as fields in your State class.

They can have a preset default value. If you don't provide a default value, you must provide a type annotation.

Start Building Now!

AAPL

Current Price: $150

Change: 4%

In this example ticker and price are base vars in the app, which can be modified at runtime.

Accessing state variables on different pages

State is just a python class and so can be defined on one page and then imported and used on another. Below we define TickerState class on the page state.py and then import it and use it on the page index.py.

# state.py


class TickerState(rx.State):
    ticker: str = "AAPL"
    price: str = "$150"
# index.py
from .state import TickerState


def ticker_example():
    return rx.center(
        rx.vstack(
            rx.heading(TickerState.ticker, as_="h2", size="3"),
            rx.text(f"Current Price: {TickerState.price}", font_size="md"),
            rx.text("Change: 4%", color="green"),
        ),
    )

Changing Defaults

A state var is a descriptor on its state class, so assigning to it through the class raises TypeError instead of replacing the var. To change a var's default, call set_default on the var's field with either a default value or a default_factory function:

import time


class WatchlistState(rx.State):
    ticker: str = "AAPL"
    symbols: list[str] = []
    opened_at: float = 0.0


WatchlistState.__fields__["ticker"].set_default("MSFT")
WatchlistState.__fields__["symbols"].set_default(["AAPL", "MSFT"])
WatchlistState.__fields__["opened_at"].set_default(default_factory=time.time)

The default applies to values not yet stored on an instance, which includes every new session and reset(). Values already stored on an instance stay the same. Pass exactly one of default and default_factory; a default_factory is called for each new instance. set_default copies a mutable default, such as a list, when you set it and gives each instance its own copy, so sessions never share it and later changes to the value you passed do not reach the default. It does not check the value against the var's annotation. A browser storage var keeps its storage name and options only with a storage value as its default, such as rx.LocalStorage("dark", name="theme"). Given a plain string, a var annotated str becomes an ordinary var, and one annotated with a storage type, such as rx.LocalStorage, stays in browser storage under the default key and options.

An inherited var belongs to the state that declared it, so changing its field also changes the default for every state that inherits it. Each generated ComponentState class owns copies of its fields, allowing get_component to configure defaults independently for each component.

In tests, patch the field rather than the class attribute, which raises the same TypeError:

from unittest import mock

with mock.patch.object(WatchlistState.__fields__["ticker"], "default", "MSFT"):
    ...

Declare class-level configuration, such as a client or a lock, as a ClassVar. It stays an ordinary class attribute, so assigning it through the class is allowed, and it is never copied for each instance. Each backend worker process holds its own value, though, so a lock only serializes the sessions on its own worker. A value set at import time, such as at module level, starts the same in every worker, but a change made after the workers start, such as in an event handler, never reaches the other workers. Keep a value that sessions must share at runtime in an rx.SharedState or an external store.

Backend-only Vars

Any Var in a state class that starts with an underscore (_) is considered backend only and will not be synchronized with the frontend. Data associated with a specific session that is not directly rendered on the frontend should be stored in a backend-only var to reduce network traffic and improve performance.

They have the advantage that they don't need to be JSON serializable, however they must still be pickle-able to be used with redis in prod mode. They are not directly renderable on the frontend, and may be used to store sensitive values that should not be sent to the client.

For example, a backend-only var is used to store a large data structure which is then paged to the frontend using cached vars.

Read and write a backend var through a state instance, such as self._token. Reading MyState._token through the class returns its field descriptor, whose default_value() method returns the default (a fresh copy if it is mutable). Use it to build the UI from a constant, such as rx.foreach(MyState._options.default_value(), rx.text) for a backend var _options. Assigning to MyState._token raises TypeError: change its default through its field as described above.

For class-level configuration, declare a ClassVar instead:

from typing import ClassVar


class MyState(rx.State):
    _endpoint: ClassVar[str] = "https://example.com/api"
    _token: str = ""


MyState._endpoint = "https://example.com/v2"

ClassVar values are ordinary class attributes and are not part of session state. Reading one on the class returns the plain value, and an object that cannot be copied, such as a client or lock, is shared rather than copied for each instance. Each backend worker holds its own value, as described under Changing Defaults.

Start Building Now!

Page 1 / 10

Page Size

    _backend[0] = 84

    _backend[1] = 64

    _backend[2] = 5

    _backend[3] = 87

    _backend[4] = 30

    _backend[5] = 96

    _backend[6] = 68

    _backend[7] = 42

    _backend[8] = 54

    _backend[9] = 68

Using rx.field / rx.Field to improve type hinting for vars

When defining state variables you can use rx.Field[T] to annotate the variable's type. Then, you can initialize the variable using rx.field(default_value), where default_value is an instance of type T.

This approach makes the variable's type explicit, aiding static analysis tools in type checking. In addition, it shows you what methods are allowed to modify the variable in your frontend code, as they are listed in the type hint.

Below are two examples:

import reflex as rx

app = rx.App()


class State(rx.State):
    x: rx.Field[bool] = rx.field(False)

    def flip(self):
        self.x = not self.x


@app.add_page
def index():
    return rx.vstack(
        rx.button("Click me", on_click=State.flip),
        rx.text(State.x),
        rx.text(~State.x),
    )

Here State.x, as it is typed correctly as a boolean var, gets better code completion, i.e. here we get options such as to_string() or equals().

import reflex as rx

app = rx.App()


class State(rx.State):
    x: rx.Field[dict[str, list[int]]] = rx.field(default_factory=dict)


@app.add_page
def index():
    return rx.vstack(
        rx.text(State.x.values()[0][0]),
    )

Here State.x, as it is typed correctly as a dict of str to list of int var, gets better code completion, i.e. here we get options such as contains(), keys(), values(), items() or merge().