Python has long had a presence as a language for server-side frameworks, with support for most every project size or use case. But it's historically been confined to the back end—there's no real culture of writing Python for creating front-end, client-side code. At least, not yet.
Recently, some projects have tried to transpile Python to JavaScript on the front end, or run Python on the front end via WebAssembly. There's promise in the idea, but the way it's currently implemented is clunky and primordial. Maybe there's a better option for developers right now?
Sure enough, there is. An emerging family of Python web frameworks let you write declarative Python code on the back end that programmatically generates front-end code. You can use Python objects to describe HTML entities and their JavaScript-powered behaviors, then let the framework generate those objects for you when they're served to the client.
Here are three web frameworks for Python that follow this paradigm. Each allows front-end code (HTML, CSS, and JavaScript) to be described by back-end Python code, so that the front-end objects are represented through the Python object model.
Anvil
Anvil's big pitch is "Build web apps with nothing but Python" (emphasis theirs). With Anvil, one writes Python code—or uses Anvil's drag-and-drop low-code tools—and out comes a full-blown web application with an interactive, JavaScript-powered front end and a Python-powered back end.
Anvil offers two basic approaches. One is the Anvil cloud service, which comes in a range of pricing tiers and offers visual build tools and a range of hosting options. The other is the open source Anvil runtime, which doesn't include the visual designer but still lets you build and run Anvil applications with hand-written code.
Anvil applications consist of three components: the UI—which can either be designed with Anvil's design tools or expressed through hand-written code—the client-side code that's transpiled from Python to JavaScript, and the server-side Python code. The Anvil cloud editor automatically generates back- and front-end code, in much the same manner as tools like Qt Design Studio.
Two ways to use Anvil
The Anvil cloud editor comes with a few included examples, such as a basic static application with no back-end code, a simple ticketing system, or a full-blown online store. Each can be used as a template for your own project. You also get a useful selection of prebuilt UI components to wire up into web pages. One handy component is a timer for executing code at intervals—e.g., for polling a data source for updates. You can also hand-roll your own HTML and custom components if you need it. Data sources can also be added in the cloud and wired up to components, so common CRUD apps can be put together very quickly.
If you elect to use the Anvil runtime, you can write applications by hand and use one of a few prebuilt templates as a starting point. Changes to the code get reflected immediately on the application server, making for a fast development cycle. User interface elements are essentially Python class instances, with event handlers added via class methods. It's also easy to programmatically add behaviors by way of well-thought-out general methods. For instance, if you want to raise an event with an object's children, you don't need to loop through the children to do it; you can simply use a raise_event_on_children
method on the container object.
By default all the JavaScript for an Anvil site is generated automatically, but you can write your own JavaScript as needed. Note that Anvil loads some JavaScript of its own that might conflict with the code you write. What's more, some of Anvil's own dependencies are somewhat dated—Bootstrap 3, for instance. You can work around it by creating a custom theme, which is not a trivial amount of work.
Pynecone
Pynecone doesn't include the design tooling you will find in Anvil, but it has the same underlying idea: You use Python code both to write the back end of your web stack and to programmatically generate the front end without needing to write JavaScript.
Pynecone itself uses both Python and at least the long-term support version of the Node.js runtime, along with the Bun JavaScript library manager. To that end, you'll need to have Node present before running pip install pynecone
. Also, Pynecone's stack is tilted somewhat in favor of Linux over Windows; it'll run on Windows, just not as well, unless you use Windows Subsystem for Linux (WSL). But once you get things set up, you can use the provided pc
command to set up a new Pynecone project template in a virtual environment and get it running.
The front end of a Pynecone application compiles to Next.js, with each of the components on a web page described using Python objects. Many common components come built-in—not just common things like text layouts or form handling, but data display objects like plots or charts, feedback controls like alerts and progress bars, and overlay objects like modals and tooltips. You can also wrap custom-built React components. For connecting to data sources, Pynecone includes a data layer that wraps the well-known SQLAlchemy ORM.
If you want to customize a UI component, most common customizations, like CSS styling, can be passed as arguments to the object constructor, rather than subclassing a component and modifying it that way. For everything else, there's custom HTML, but some combination of the built-ins and their options should suffice for the vast majority of common projects. A built-in memoizing decorator lets you avoid re-rendering components, but the decorator doesn't let you control the size or lifetime of its cache.
Finally, if you build chiefly static sites, Pynecone has the handy ability to export an entire site to a static build. This makes Pynecone useful as a programmatic site generator tool, as well.
JustPy
Like Pynecone, JustPy lets you programmatically construct elements on web pages, although it has no interactive design tools. What makes JustPy stand out is its efficient and sensible object model.
For instance, we can create a jp.Ul
list object l
, then add elements to it by defining new objects with the parent l
specified via an argument. This makes it easy to build lists using for
loops without having to append objects to some container, so the resulting code is clean and easy to parse. All of JustPy's objects can be subclassed and modified; the documentation provides several examples.
Registering event handlers for elements, like on-click actions, involves little more than writing a Python function that takes self
as a first argument (for the object in question). Event handlers can also have "before" or "after" events for further flexibility. If you want live updates to the front end via WebSockets, JustPy offers that as the default, but you can use Ajax updates as well.
JustPy uses Tailwind for CSS, which uses composable utility classes for styling, but you can disable Tailwind and swap in another CSS framework (minus JustPy's natural integration) if needed. You can also insert HTML directly in a number of ways—by setting an inner_html
attribute on an object, by directly injecting HTML at the page level, or by parsing raw HTML into an object stream. Entire pages, or individual objects, can also be cached for re-use.
Another standout feature is integration for a slew of front-end presentation frameworks: Matplotlib, Plotly, Altair, Bokeh, just to name a few. This makes JustPy well-suited to wrapping Python code for data science and presenting it via a web interface. Each object, like a Matplotlib plot, is delivered as a JustPy object that can be added to any page's collection of objects.
Some things aren't included. JustPy does not include an ORM or other data layer as part of its stack. This is no great omission, as ORMs and data layers are easy enough to add after the fact in any modern web framework. But there is also no direct equivalent to a simple templating system like Jinja2, and no included option for a fully static website deployment.
Conclusion
Looking at the three frameworks in sum, Anvil's big draw is its low- and no-code interactive UI creation tools, while JustPy offers a compact way to express how objects are created and interrelated. Pynecone, meanwhile, provides the convenience of working with React components and Next.js, and it lets you render generated sites to static HTML.