search
HomeBackend DevelopmentPython TutorialDesigning a Pure Python Web Framework

Web development is one of the most popular use cases for programming. Python is one of the most popular programming languages in the world. So why can't we build web apps in Python?

Making a UI should be simple, but even you have great engineers on your team, the overhead of learning a new language and tools was a huge barrier. Often making a UI could be harder than the actual work one is doing!

TLDR

Under the hood, Reflex apps compile down to a React frontend app and a FastAPI backend app. Only the UI is compiled to Javascript; all the app logic and state management stays in Python and is run on the server. Reflex uses WebSockets to send events from the frontend to the backend, and to send state updates from the backend to the frontend.

Existing Python Solutions

There were a few ways already to build apps in Python, but none of them fit our needs.

On the one hand, there are frameworks like Django and Flask that are great for building production-grade web apps. But they only handle the backend - you still need to use JavaScript and a frontend framework, as well as writing a lot of boilerplate code to connect the frontend and backend.

On the other hand, pure Python libraries like Dash and Streamlit can be great for small projects, but they are limited to a specific use case and don't have the features and performance to build a full web app. As your app grows in features and complexity, you may find yourself hitting the limits of the framework, at which point you either have to limit your idea to fit the framework, or scrap your project and rebuild it using a "real web framework".

We want to bridge this gap by creating a framework that is easy and intuitive to get started with, while remaining flexible and powerful to support any app.

Goals of Reflex

  • Pure Python: Use one language for everything.
  • Easy to get started: Build your ideas easily without needing web development experience.
  • Full flexibility: Web apps should match the customizability and performance of traditional web frameworks.
  • Batteries included: Handle the full-stack from the frontend, to the backend, to deployment.

Now let's dive into how we built Reflex to meet these goals.

The Reflex Architecture

Full-stack web apps are made up of a frontend and a backend. The frontend is the user interface, and is served as a web page that runs on the user's browser. The backend handles the logic and state management (such as databases and APIs), and is run on a server.

In traditional web development, these are usually two separate apps, and are often written in different frameworks or languages. For example, you may combine a Flask backend with a React frontend. With this approach, you have to maintain two separate apps and end up writing a lot of boilerplate code to connect the frontend and backend.

We want to simplify this process in Reflex by defining both the frontend and backend in a single codebase, while using Python for everything. Developers should only worry about their app's logic and not about the low-level implementation details.

Designing a Pure Python Web Framework

Frontend

We want Reflex apps to look and feel like a traditional web app to the end user, while still being easy to build and maintain for the developer. To do this, we built on top of mature and popular web technologies.

When you reflex run your app, Reflex compiles the frontend down to a single-page Next.js app and serves it on a port (by default 3000) that you can access in your browser.

The frontend's job is to reflect the app's state, and send events to the backend when the user interacts with the UI. No actual logic is run on the frontend.

Components

Reflex frontends are built using components that can be composed together to create complex UIs. Instead of using a templating language that mixes HTML and Python, we just use Python functions to define the UI.

Under the hood, components compile down to React components.

Many of our core components are based on Radix, a popular React component library. We also have many other components for graphing, datatables, and more.

We chose React because it is a popular library with a huge ecosystem. Our goal isn't to recreate the web ecosystem, but to make it accessible to Python developers.

This also lets our users bring their own components if we don't have a component they need. Users can wrap their own React components and then publish them for others to use. Over time we will build out our third party component ecosystem so that users can easily find and use components that others have built.

Styling

We wanted to make sure Reflex apps look good out of the box, while still giving developers full control over the appearance of their app.

We have a core theming system that lets you set high level styling options such as dark mode and accent color throughout your app to give it a unified look and feel.

Beyond this, Reflex components can be styled using the full power of CSS. We leverage the Emotion library to allow "CSS-in-Python" styling, so you can pass any CSS prop as a keyword argument to a component. This includes responsive props by passing a list of values.

Backend

In Reflex only the frontend compiles to Javascript and runs on the user's browser, while all the state and logic stays in Python and is run on the server. When you reflex run, we start a FastAPI server (by default on port 8000) that the frontend connects to through a websocket.

All the state and logic are defined within a State class.

The state is made up of vars and event handlers.

Vars are any values in your app that can change over time. They are defined as class attributes on your State class, and may be any Python type that can be serialized to JSON.

Event handlers are methods in your State class that are called when the user interacts with the UI. They are the only way that we can modify the vars in Reflex, and can be called in response to user actions, such as clicking a button or typing in a text box.

Since event handlers are run on the backend, you can use any Python library within them.

Designing a Pure Python Web Framework

Event Processing

Normally when writing web apps, you have to write a lot of boilerplate code to connect the frontend and backend. With Reflex, you don't have to worry about that - we handle the communication between the frontend and backend for you. Developers just have to write their event handler logic, and when the vars are updated the UI is automatically updated.

Event Triggers

The user can interact with the UI in many ways, such as clicking a button, typing in a text box, or hovering over an element. In Reflex, we call these event triggers.

Event Queue

On the frontend, we maintain an event queue of all pending events. An event consists of three major pieces of data:

  • client token: Each client (browser tab) has a unique token to identify it. This let's the backend know which state to update.
  • event handler: The event handler to run on the state.
  • arguments: The arguments to pass to the event handler.

When an event is triggered, it is added to the queue.
We have a processing flag to make sure only one event is processed at a time. This ensures that the state is always consistent and there aren't any race conditions with two event handlers modifying the state at the same time. There are exceptions to this, such as background events which allow you to run events in the background without blocking the UI.

Once the event is ready to be processed, it is sent to the backend through a WebSocket connection.

State Manager

Once the event is received, it is processed on the backend.

Reflex uses a state manager which maintains a mapping between client tokens and their state. By default, the state manager is just an in-memory dictionary, but it can be extended to use a database or cache. In production we use Redis as our state manager.

Event Handling

Once we have the user's state, the next step is to run the event handler with the arguments.

State Updates

Every time an event handler returns (or yields), we save the state in the state manager and send the state updates to the frontend to update the UI.

To maintain performance as your state grows, internally Reflex keeps track of vars that were updated during the event handler (dirty vars).
When the event handler is done processing, we find all the dirty vars and create a state update to send to the frontend.

We store the new state in our state manager, and then send the state update to the frontend.
The frontend then updates the UI to reflect the new state.

Conclusion

I hope this provides a good overview of how Reflex works under the hood. We will have more posts coming out to share how we made Reflex scalable and performant through features such as state sharding and compiler optimizations.

The above is the detailed content of Designing a Pure Python Web Framework. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Are Python lists dynamic arrays or linked lists under the hood?Are Python lists dynamic arrays or linked lists under the hood?May 07, 2025 am 12:16 AM

Pythonlistsareimplementedasdynamicarrays,notlinkedlists.1)Theyarestoredincontiguousmemoryblocks,whichmayrequirereallocationwhenappendingitems,impactingperformance.2)Linkedlistswouldofferefficientinsertions/deletionsbutslowerindexedaccess,leadingPytho

How do you remove elements from a Python list?How do you remove elements from a Python list?May 07, 2025 am 12:15 AM

Pythonoffersfourmainmethodstoremoveelementsfromalist:1)remove(value)removesthefirstoccurrenceofavalue,2)pop(index)removesandreturnsanelementataspecifiedindex,3)delstatementremoveselementsbyindexorslice,and4)clear()removesallitemsfromthelist.Eachmetho

What should you check if you get a 'Permission denied' error when trying to run a script?What should you check if you get a 'Permission denied' error when trying to run a script?May 07, 2025 am 12:12 AM

Toresolvea"Permissiondenied"errorwhenrunningascript,followthesesteps:1)Checkandadjustthescript'spermissionsusingchmod xmyscript.shtomakeitexecutable.2)Ensurethescriptislocatedinadirectorywhereyouhavewritepermissions,suchasyourhomedirectory.

How are arrays used in image processing with Python?How are arrays used in image processing with Python?May 07, 2025 am 12:04 AM

ArraysarecrucialinPythonimageprocessingastheyenableefficientmanipulationandanalysisofimagedata.1)ImagesareconvertedtoNumPyarrays,withgrayscaleimagesas2Darraysandcolorimagesas3Darrays.2)Arraysallowforvectorizedoperations,enablingfastadjustmentslikebri

For what types of operations are arrays significantly faster than lists?For what types of operations are arrays significantly faster than lists?May 07, 2025 am 12:01 AM

Arraysaresignificantlyfasterthanlistsforoperationsbenefitingfromdirectmemoryaccessandfixed-sizestructures.1)Accessingelements:Arraysprovideconstant-timeaccessduetocontiguousmemorystorage.2)Iteration:Arraysleveragecachelocalityforfasteriteration.3)Mem

Explain the performance differences in element-wise operations between lists and arrays.Explain the performance differences in element-wise operations between lists and arrays.May 06, 2025 am 12:15 AM

Arraysarebetterforelement-wiseoperationsduetofasteraccessandoptimizedimplementations.1)Arrayshavecontiguousmemoryfordirectaccess,enhancingperformance.2)Listsareflexiblebutslowerduetopotentialdynamicresizing.3)Forlargedatasets,arrays,especiallywithlib

How can you perform mathematical operations on entire NumPy arrays efficiently?How can you perform mathematical operations on entire NumPy arrays efficiently?May 06, 2025 am 12:15 AM

Mathematical operations of the entire array in NumPy can be efficiently implemented through vectorized operations. 1) Use simple operators such as addition (arr 2) to perform operations on arrays. 2) NumPy uses the underlying C language library, which improves the computing speed. 3) You can perform complex operations such as multiplication, division, and exponents. 4) Pay attention to broadcast operations to ensure that the array shape is compatible. 5) Using NumPy functions such as np.sum() can significantly improve performance.

How do you insert elements into a Python array?How do you insert elements into a Python array?May 06, 2025 am 12:14 AM

In Python, there are two main methods for inserting elements into a list: 1) Using the insert(index, value) method, you can insert elements at the specified index, but inserting at the beginning of a large list is inefficient; 2) Using the append(value) method, add elements at the end of the list, which is highly efficient. For large lists, it is recommended to use append() or consider using deque or NumPy arrays to optimize performance.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor