Preswald: build Python data apps that compile to a single shareable HTML folder
Preswald is a WASM packager for Python-based interactive data apps: bundle full complex data workflows, particularly visualizations, into single files, runnable completely in-browser, using Pyodide, DuckDB, Pandas, and Plotly, Matplotlib, etc. Build dashboards, reports, and notebooks that run offline, load fast, and share like a document.
At a glance
- What is it?
- Preswald is a static-site generator for Python data apps. It bundles your code, data and DuckDB queries into a dist/ folder that runs in the browser with Pyodide, and the trade-off is that everything you ship also ships to whoever opens the file.
- Who is it for?
- Adopt Preswald if you need to hand a stakeholder a folder that opens in a browser with no install and no server, and if the data inside it is allowed to travel with it. Skip it if your app needs a live database connection, server-side secrets, or a dataset too large to load into a browser tab.
- Can I use it commercially?
- Yes. Apache-2.0 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 111 days 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 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Preswald solves, and for whom
The problem is distribution, not computation. A Python analyst can build a dashboard in an afternoon and then spend a week explaining to a stakeholder how to install Python, create a virtual environment, and run a server. Preswald's answer is to make the app a file. The README describes it as a "static-site generator for building interactive data apps in Python" that packages compute, data access, and UI into self-contained apps running locally in the browser.
The audience is narrow and identifiable. The README lists the cases it is built for: bundling logic, UI and data into a shareable file; shipping a tool to someone who should not need to install anything; working with sensitive data where you want local control; and giving AI systems structured, modifiable tools. That last one is unusual and worth reading literally. Because a Preswald app is Python source plus a TOML config, an agent can inspect and rewrite it the way it would rewrite any other file in a repository.
The people who benefit most are analysts and data engineers who already write pandas and want a delivery format that is not a notebook and not a deployed web service. The people who will be disappointed are those looking for a hosted dashboard product. Preswald produces a folder, not a service.
How the browser runtime actually works
Preswald is not a Python-to-JavaScript transpiler. It ships a WASM runtime built on Pyodide and DuckDB, so the Python interpreter and the analytical database both run inside the browser tab. Your app code executes there, against data bundled with it.
The reactive layer is a dependency graph. The README calls it a "reactive engine" that only re-runs what is needed, "powered by a DAG of dependencies," and networkx is a declared dependency in pyproject.toml, which is consistent with graph-based scheduling. When a widget changes, Preswald walks the graph and re-executes the affected cells rather than the whole script. That is the same mental model as a reactive notebook, and it is the part that determines whether an app feels responsive or sluggish.
The dependency list also shows the split between build-time and run-time. FastAPI, uvicorn and websockets are marked server-only with the environment marker platform_system != 'Emscripten', so they are excluded from the browser build. DuckDB, pandas, plotly and matplotlib are unconditional. That tells you the intended shape: a local development server for authoring, and a WASM bundle for delivery.
The packaging step is preswald export, which the README says builds the app into a static site inside dist/ containing "all the files needed to run your app locally or share it." The README states the export bundles your Python code via Pyodide, your data, and your DuckDB queries, and preserves UI, logic and reactive state.
Installing Preswald and running a first app
Preswald is published on PyPI and requires Python 3.10 or newer according to pyproject.toml, though the README badge advertises 3.7+. Trust the package metadata over the badge.
pip install preswaldThe README also gives the uv form:
uv pip install preswaldScaffold a project and start the development server. The init command creates a folder with your app logic, configuration, a secrets file, sample data and a logo.
preswald init my_app
cd my_app
preswald runThe README says the development server typically reports the app at http://localhost:8501, and that port is also the default in preswald.toml. The generated hello.py shows the component model: import functions, load a dataframe, render it.
from preswald import text, table, get_df
text("# Hello Preswald")
df = get_df("sample.csv")
table(df)The configuration file controls metadata, branding, logging and the port:
[project]
title = "Preswald Project"
version = "0.1.0"
port = 8501
slug = "preswald-project"
entrypoint = "hello.py"When the app does what you want, produce the deliverable:
preswald exportThat writes the static site into dist/. The README says the result works offline in any modern browser and can be shared as a folder or embedded in a hosting platform.
The data travels with the app, and that cuts both ways
This is the limitation that matters most, and the README is honest about it without spelling out the consequence. Because the export bundles data and DuckDB queries into the static site, anything in the bundle is readable by anyone who opens the folder. The README's claim of being "secure by default" rests on the app running locally rather than on any access control. Local execution protects you from sending data to a third party. It does not protect the data from the recipient.
So the sensitive-data use case has a boundary. If your goal is that a colleague can explore a dataset on their own machine without it leaving the building, Preswald fits. If your goal is that a colleague can explore a dataset they are not allowed to keep, Preswald is the wrong tool, because the dataset is inside the artifact you just handed them.
Size is the second constraint. Pyodide and DuckDB run in a browser tab, and the whole bundle has to be downloaded and initialized before the first render. The README claims the apps run offline "even with large data," but it does not define large, and there is no published figure for startup time against a given row count. Treat the size ceiling as something you must measure on your own files rather than something the documentation settles.
Third, the README does not document rollback. There is no described way to revert an exported app to a previous state, and the CHANGELOG is the only place version history is recorded. If you ship these files to stakeholders, you are managing versions yourself.
Preswald against Streamlit and Dash
The obvious comparison is Streamlit, and the difference is architectural rather than cosmetic. Streamlit runs a Python server process and the browser is a thin client that talks to it. Preswald moves the interpreter into the browser. That single choice explains everything else: no server to deploy, no network round trip per interaction, and no live connection to a database or a filesystem outside the bundle.
Dash makes a similar server-side bet with a callback model on top of Flask. Preswald's reactive engine is a dependency graph, which is closer in spirit to a reactive notebook than to Dash's explicit callback wiring.
The practical consequence is that Streamlit and Dash can read from a production warehouse on every page load, and Preswald cannot. If your dashboard must show yesterday's numbers from a live source, the server-based tools are the right answer and Preswald is not. If your dashboard is a snapshot that should keep working on a plane, Preswald is the one that fits. There is also a middle option worth naming: exporting to a static site with something like Quarto or Voila. Those keep the server model and give you a shareable artifact, but they do not remove the runtime dependency the way a WASM bundle does.
Maintenance, releases and the Apache-2.0 licence
The repository is not archived and the last push was on 2026-06-11, which is roughly three months before this writing. That is recent enough to suggest the project is still receiving changes, but the release cadence tells a different story. The three most recent releases are v0.1.57, v0.1.58 and v0.1.59, dated 2025-05-29, 2025-05-29 and 2025-06-05. The gap between the last tagged release and the last commit is about a year. Commits are landing; tagged releases are not. If your upgrade policy keys off PyPI versions rather than the main branch, plan for long stretches without a new one.
Upgrade cost is low by design. The version lives in pyproject.toml and the Makefile's update-version target increments the patch number automatically, so the maintainers are on a patch-bump treadmill rather than a semantic-versioning schedule. For a 0.x project that is reasonable, but it means a patch number carries no promise about compatibility. Pin the version in your own environment and read CHANGELOG.md before moving.
The licence is Apache-2.0, declared both in the LICENSE file and in pyproject.toml. That is a permissive licence with an explicit patent grant, which matters if you are embedding the output in a commercial product. What it does not settle is the licensing of the data you bundle into an exported app. That is your data and your obligation, and the repository says nothing about it. This is not legal advice; if you are shipping exported apps outside your organisation, get the question answered by someone qualified.
Editorial conclusion
Adopt Preswald if you need to hand a stakeholder a folder that opens in a browser with no install and no server, and if the data inside it is allowed to travel with it. Skip it if your app needs a live database connection, server-side secrets, or a dataset too large to load into a browser tab. Before committing, run preswald export on your real dataset and open dist/ from a file path with the network disabled, then read preswald.toml to confirm which port and entrypoint the build is actually using.
Frequently asked questions
What is Preswald used for?
It builds interactive data apps in Python and exports them as a static site in dist/ that runs in the browser. The README lists analyst dashboards, interactive reports, data inspection tools, offline kits and experiment panels as the intended uses.
Does Preswald need a server to run the exported app?
No. The README states the exported app runs offline in any modern browser, with Python provided by Pyodide and queries handled by DuckDB inside the page. The FastAPI and uvicorn dependencies are marked server-only and excluded from the browser build.
What Python version does Preswald require?
pyproject.toml declares requires-python as >=3.10, while the README badge advertises Python 3.7 or newer. The package metadata is the stricter and more reliable of the two.
Official sources
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.
[](https://hysenlabs.com/projects/structuredlabs-preswald)