Self-hosted service
zauberzeug/nicegui avatar
zauberzeug/nicegui

NiceGUI: Python Web UIs Without the State Magic

Create web-based user interfaces with Python. The nice way.

16,254 stars954 forksPythonMIT

At a glance

What is it?
NiceGUI builds browser interfaces from plain Python on top of FastAPI and Vue, and the README is explicit about which framework it was written to replace. Here is how the install works, where the design stops helping, and how it differs from Streamlit.
Who is it for?
Adopt NiceGUI for internal dashboards, robotics control panels and machine-learning tweaking tools where the people using the page are also the people writing it, and where a FastAPI process on port 8080 is an acceptable deployment shape. Do not adopt it if you need a statically hosted frontend, if your team wants a component library with a formal design system behind it, or if the interface will be handed to frontend engineers who will not read Python.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What NiceGUI is for, and the framework it was written against

NiceGUI is a Python package that renders a user interface in a web browser. The README lists its intended ground as micro web apps, dashboards, robotics projects and smart home solutions, and adds a second use case that is easy to overlook: development tooling, such as tweaking a machine learning algorithm or tuning motor controllers. That second case explains a lot of the design. The audience is people who write Python and want a control surface for something, not people who want to build a product frontend.

The project's own justification is unusually direct. The maintainers state that they like Streamlit but find it does too much magic when it comes to state handling, and that they found JustPy too low-level in its HTML approach. NiceGUI sits between those two positions: you describe elements imperatively in Python, but you do not write HTML, and the framework keeps a live connection to the browser rather than re-running a script from the top on every interaction.

How the Python-to-browser pipeline actually works

The stack is documented in the README's Why section. NiceGUI builds on FastAPI, which itself sits on Starlette and Uvicorn. The frontend uses Vue and Quasar, and the dependency list in package.json pins quasar at 2.18.5, vue at 3.5.22 and socket.io at 4.8.1. So a running NiceGUI app is an ASGI web server that serves a Vue single-page application and exchanges events with it over a socket connection.

That architecture produces the behaviour that distinguishes NiceGUI from a request-response web framework. When you write ui.button('BUTTON', on_click=lambda: ui.notify('button was pressed')), the button exists in the browser but the callback runs in your Python process. The README describes the app as acting either as a webserver accessed by the browser or in native mode as a desktop window, and it lists per-user and general persistence, custom routes and data responses, lifecycle events and session data as features. The same process can therefore serve ordinary FastAPI routes alongside the UI.

The element set is broader than a form toolkit. The feature list names 3D scenes, plots and charts, virtual joysticks for steering events, image annotation and overlay, tables, foldable trees, and embedded video and audio. There is a built-in timer described as able to refresh data at intervals, with the README citing 10 ms as the fastest interval. A pytest-based testing framework is included. The maintainers also ship nicegui/llms.md as a concise reference inside the package, served at https://nicegui.io/llms.txt, which is a practical detail if you plan to have an assistant write UI code against the API.

Installing NiceGUI and getting a first page on port 8080

Installation is a single pip command, and the README gives no virtualenv or system-package prerequisites beyond that. The package requires Python 3.10 or newer and below 4.0, according to pyproject.toml, and it is also published as a Docker image and on conda-forge.

bash
python3 -m pip install nicegui

The first real use is a file the README calls main.py. It imports ui, places a label and a button, and calls ui.run() at the end. The button's on_click is a lambda that calls ui.notify, which is the framework's built-in notification mechanism rather than a hand-rolled alert.

python
from nicegui import ui

ui.label('Hello NiceGUI!')
ui.button('BUTTON', on_click=lambda: ui.notify('button was pressed'))

ui.run()

Launch it with the interpreter, and the README states the GUI is then available at http://localhost:8080/. Clicking the button should produce a notification in the browser. The README also notes that NiceGUI reloads the page automatically when you modify the code, so the edit-run cycle does not require restarting the process manually.

bash
python3 main.py

If you prefer not to install anything locally, the README points at the Docker image for the project's own website and gives docker run -p 8080:8080 zauberzeug/nicegui as the way to start it. That runs the documentation site itself, which the README says is implemented with NiceGUI.

Where the abstraction stops helping

The live-socket model is the source of NiceGUI's main constraints. Every connected browser holds a session in the Python process, and the README lists session data and per-user persistence as features, which means state lives in memory by default. The README does not document a scaling story for many concurrent sessions, and it does not describe a horizontal scaling mechanism. For a dashboard used by five colleagues or a control panel attached to one robot, that is irrelevant. For a public page with unpredictable traffic, it is the first question to answer before writing code.

The frontend dependencies are pinned to exact versions in package.json, including quasar 2.18.5, vue 3.5.22 and socket.io 4.8.1. That pinning is deliberate, since the Python side generates elements that the Vue side must understand, but it also means a security advisory in any of those packages has to be resolved by the maintainers rather than by your own dependency bump. The overrides block already forces ws to a minimum of 8.20.1, which suggests this class of problem is understood. It is still a coupling you inherit.

A third limitation is conceptual rather than technical. NiceGUI gives you general-purpose HTML and Markdown elements and Tailwind CSS autocomplete, but it is not a design system. If a designer hands you a component specification, you will be translating it into rows, columns, cards and dialogs. The README does not document a theming mechanism beyond defining primary, secondary and accent colors.

NiceGUI vs Streamlit: the difference is where state lives

The comparison is not hypothetical, because the README names Streamlit as the framework the maintainers were using when they decided to build something else. The stated objection is state handling: Streamlit's model re-executes your script on each interaction, which the maintainers describe as too much magic. NiceGUI instead keeps a persistent object graph per session and mutates it. A button callback is a function that runs once, not a script that runs again from the top.

That changes what code looks like. In a re-run model you have to think about what survives between runs and reach for caching or session-state primitives. In NiceGUI you hold a reference to an element and update it. The README's data binding and refreshable functions are aimed at exactly this, described as a way to write even less code.

The trade is that you now own a long-lived process with mutable state, which is a different operational problem from a stateless script. NiceGUI also inherits FastAPI, so adding an API endpoint next to the UI is a normal thing to do, and the examples directory contains a fastapi example and an api_requests example. The README does not claim Streamlit is worse in general, only that its state model did not fit the maintainers' daily work.

Maintenance, licence and the cost of upgrading

NiceGUI is MIT licensed, stated in both the README badge and the license field of pyproject.toml. MIT permits commercial use, modification and redistribution with the licence text retained. That is a permissive arrangement with no copyleft obligation, but it is not legal advice and your own counsel should confirm how it interacts with anything you bundle.

The repository is not archived, and the last push was on 2026-09-18, three days before this writing. Releases are frequent: v3.17.1 on 2026-09-18, v3.17.0 on 2026-09-16, and v3.16.0 on 2026-08-12. The 3.x line is moving quickly, and the README does not document a deprecation policy or a rollback procedure. If you pin a version, read the release notes between your pin and the next upgrade before moving, because a fast minor-release cadence on a framework that owns both sides of a client-server protocol is the kind of thing that occasionally breaks an API you were relying on.

Upgrade cost is also shaped by the pinned frontend packages. A NiceGUI upgrade may pull a different Quasar or Vue version, and your custom CSS or custom Vue components are the parts most likely to notice. The examples directory includes a custom_vue_component example, which is the escape hatch when the built-in elements are not enough, and also the place where version coupling bites hardest.

Editorial conclusion

Adopt NiceGUI for internal dashboards, robotics control panels and machine-learning tweaking tools where the people using the page are also the people writing it, and where a FastAPI process on port 8080 is an acceptable deployment shape. Do not adopt it if you need a statically hosted frontend, if your team wants a component library with a formal design system behind it, or if the interface will be handed to frontend engineers who will not read Python. Before committing, verify the pinned frontend dependencies in package.json against your own supply-chain rules, and check whether the per-user state model in the documentation matches how many concurrent sessions you actually expect.

Frequently asked questions

What is NiceGUI used for?

It creates browser-based user interfaces from Python. The README names micro web apps, dashboards, robotics projects and smart home solutions, and adds development use cases such as tweaking a machine learning algorithm or tuning motor controllers.

Is NiceGUI free to use?

Yes. The project is MIT licensed according to the README badge and the license field in pyproject.toml, which permits commercial use and modification with the licence text retained.

What are the key differences between NiceGUI and Streamlit?

The maintainers state they liked Streamlit but found it did too much magic with state handling. NiceGUI keeps a persistent element graph per session and runs callbacks once, rather than re-executing your script on every interaction.

Does NiceGUI use FastAPI?

Yes. The README states NiceGUI is built on top of FastAPI, which itself is based on Starlette and Uvicorn. FastAPI appears as a direct dependency in pyproject.toml, and the examples directory contains a fastapi example.

How do I install NiceGUI?

Run python3 -m pip install nicegui. The README also lists a Docker image and a conda-forge package as alternative distribution channels, and pyproject.toml requires Python 3.10 or newer.

Is NiceGUI production ready?

The project classifies itself as Production/Stable in pyproject.toml and the README lists per-user persistence and lifecycle events as features. The README does not document a horizontal scaling or multi-instance session story, so verify that against your concurrency expectations before deploying.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. zauberzeug/nicegui on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zauberzeug-nicegui.svg)](https://hysenlabs.com/projects/zauberzeug-nicegui)