stlitepack Quickstart Guide

This guide walks you through packaging a Streamlit app into a static stlite app and publishing it on GitHub Pages.

Stlite is a WebAssembly-powered reimplementation of Streamlit that runs entirely in the browser using Pyodide. This means Streamlit apps can be distributed as static HTML files without requiring a Python backend server.

The stlitepack package helps automate the process of packaging your existing Streamlit apps into a stlite-compatible format, so you can publish and share them easily while writing and previewing your Streamlit apps like normal.

Compared to traditional server-deployed Streamlit apps, where the actual computation happens on a web server somewhere, and hosting options for such apps like Streamlit Community Cloud, Pyodide-powered stlite apps offer some unique advantages:

Why stlitepack?

stlite requires saving your streamlit app code into a html file, with some additional html code before and after the app to ensure various things are loaded in.

However, this makes it harder to

  • test your app (as you can no longer run it with streamlit run)
  • debug your app (as you no longer get the standard hinting, error highlighting and syntax colouring you would in a .py file)
  • manage complex apps (as growing codebases lead to very large file)

When you then come to host it on a site like github pages, you have to remember extra steps like

  • ensuring your html file was called the right thing so github pages could find it
  • creating a .nojekyll file to avoid extra processing being done to your app

stlitepack grew out of a need to be able to develop Streamlit apps as normal, and then streamline the process of getting them up and hosted as quickly as possible. With just two key commands – pack() and setup_github_pages() - you can take a streamlit app and turn it into a hosted stlite app on github pages.

Installation

stlitepack is available on pypi (conda forge coming soon!)

pip install stlitepack

Packing Your App

To pack your app, make a new .py file in the same folder as your app.

Tip

This is easiest if your main app file is in the root (top-level) folder of your repository - if it is not, check out this packing file for an example of how to deal with it.

The pack function converts a Streamlit app into a single index.html file that can be served as a static website.

Example

from stlitepack import pack

pack(
    app_file="streamlit_app.py"
)

Running this will create a new index.html file that is a full stlite app:

docs/index.html

The package handles all the additional boilerplate html, as well as applying some common stlite-specific corrections that ensure features like streamlit spinners and material-ui icons work correctly.

By default, the index.html file is put in the docs folder to keep everything tidy, and because this is a folder github pages can easily be configured to look for.

Alternatively, you may wish for the output index.html file to be placed in a different subfolder if your chosen static hosting site expects it to be somewhere else.

from stlitepack import pack

pack(
    app_file="streamlit_app.py",
    output_dir="my_other_folder"
)

This will create:

my_other_folder/
  └── index.html

If you want to put it one level up from the current location, you can make your packing file in the same location as the app file (making sure you then run the packing file from that location using the cd command or similar), and then use ".." as the path to tell the package to place the output file one level up.

from stlitepack import pack

pack(
    app_file="streamlit_app.py",
    output_dir=".."
)

This will create:

index.html
app/
  └── streamlit_app.py
  └── my_packing_file.py
Tip

Note that if you are hosting on github pages and enabling this via the repository settings, there are only two options for where the index.html file can be stored

  • your repository’s ‘root’ folder (i.e. the top-level folder you see when you first open up your repository on github)
  • the docs folder, which must be directly within the root folder
⚠️ Important Note for Local Testing

If you open index.html directly in your browser (i.e. via file://), you may see errors like:

Failed to execute 'pushState' on 'History'
GET http://stlite.invalid/... net::ERR_NAME_NOT_RESOLVED

Don’t worry! These errors are caused by browser security restrictions and do not indicate a problem with the app.

To run the app correctly, you need to serve it over HTTP/HTTPS.

If you add the argument run_preview_server=True to your packing function, the app will automatically be previewed - though remember to close the server with CTRL + C if you’ve got extra steps in your packing file.

Alternatively, you can start the server yourself:

Once served over HTTP, navigation and media files will work as expected.

Deploying the app to GitHub Pages or any web server will automatically avoid these errors.


Key Parameters

To package up a Python app, the minimum we need to provide is the name of the main Streamlit app file (which is also known as the ‘entrypoint’). This can be called anything, but must be a .py file.

If your app has multiple additional pages stored in a pages subfolder at the same level as your main app file, then they will automatically be included in the output file.

Main Optional Parameters

requirements

You may wish to install some additional python packages.

  • a list of Python package names (["pandas", "numpy"]), or
  • a path to a requirements.txt file.

e.g.

from stlitepack import pack

pack(
    app_file="streamlit_app.py",
    requirements=["matplotlib", "numpy"],
)

or

from stlitepack import pack

pack(
    app_file="streamlit_app.py",
    requirements="requirements.txt",
)

If omitted, no extra packages are installed.

Warning

Note that due to the way packages are managed in stlite, using pyodide and micropip, you may* not be able to ‘pin’ certain dependencies in the way you are used to with streamlit apps.

More detail about this will be added soon.

Warning

In particular, it’s not possible to specify a version of the Streamlit package - this will be ignored by stlite!

Pandas, numpy, scipy and other common packages that are not pure python are other packages where issues may be encountered.

title

This controls the name of the app that will be displayed when a user has it open in a web browser, showing up as the name of the tab.

from stlitepack import pack

pack(
    app_file="streamlit_app.py",
    title="My Amazing App"
)
stylesheet_version / js_bundle_version

Version numbers of the stlite JavaScript and CSS bundles. Must be valid versions from the stlite releases page. This will control the Streamlit version that is used too.

Tip

The package will default to “0.80.5”, which is known to be particularly stable.

from stlitepack import pack

pack(
    app_file="streamlit_app.py",
    # It's highly recommended to use the same version for both arguments!
    stylesheet_version="0.84.1",
    js_bundle_version="0.84.1"
)

If you want to see the list of valid stlite versions:

from stlitepack.pack import get_stlite_versions

get_stlite_versions()
extra_files_to_embed

Extra files (relative paths) to mount inside the app, e.g. a .streamlit/config.toml or extra helper scripts.

e.g.

from stlitepack import pack

pack(
    app_file="streamlit_app.py",
    extra_files=[".streamlit/config.toml", "data.csv"]
)
Tip

Note that this must be passed as a list of strings (even if you’re only adding one extra file this way).

Tip

Also note that you don’t need to manually add extra app pages from your pages subfolder this way - they will automatically be picked up when you pass in the path of your main/entrypoint file.

Warning

At present, this only really works with text-based files, like .py, .toml, .yml, .csv, etc.

It will try to convert binary file types like .jpg, .png, .mp4 etc. into an embeddable format, but this is experimental and will increase the size of your index.html file significantly

If you need to include these kinds of files, it’s recommended to use extra_files_to_link instead.

run_preview_server

Setting run_preview_server to true will automatically preview your stlite app in a new browser window so you can check it works as expected.

Rremember to close the server with CTRL + C if you’ve got extra steps in your packing file.


Publishing with GitHub Pages

Use setup_github_pages() to scaffold a GitHub Pages deployment for your packaged stlite app.

It creates the necessary files and prints step-by-step instructions (also saved to PAGES_SETUP.md).

Prerequisites

  • You have a GitHub account and a repository for your app.
  • You know which branch you’ll publish from (default: main).
GitHub Basics
  • Repositories are project folders hosted on GitHub. You’ll need to push your code there first.
  • Branches are parallel versions of your repository (most often "main").
  • GitHub Pages is a free hosting service for static sites from your repo.

Typical workflow

from stlitepack import pack, setup_github_pages

# 1) Pack your app into docs/index.html (recommended for Pages)
pack(
    app_file="streamlit_app.py",
    requirements=["matplotlib"],
    output_dir="docs"
)

# 2) Scaffold GitHub Pages
setup_github_pages(
    mode="gh-actions",     # or "manual"
    use_docs=True,         # serve from /docs (recommended) - matches the pack default
    only_on_index=True,    # only trigger a pages rebuild when index.html changes
    branch="main"
)

# 3) Follow the printed instructions (also saved to PAGES_SETUP.md).

What the function creates

  • A .nojekyll file in the repo root (disables Jekyll so files are served as-is).
  • A 404.html file in the same folder as your index.html file (due to the way navigation works in stlite, this ensures users won’t see a 404 page not found error when refreshing while on a subpage of your app, or if they share or bookmark a link to a subpage)
  • If mode="gh-actions":
    • A workflow file at .github/workflows/deploy.yml.
    • A PAGES_SETUP.md helper with the exact steps to enable Pages via GitHub Actions.
  • If mode="manual":
    • A PAGES_SETUP.md helper with exact steps to configure Deploy from a branch.

Finishing steps (by mode)

These are also given in PAGES_SETUP.md, but are reproduced here for simplicity

If mode="manual"

  1. Commit index.html, .nojekyll and 404.html

  2. In Repo → Settings → Pages:

    • Build and deployment → Source: Deploy from a branch
    • Branch: your branch (e.g., main)
    • Folder: /docs (if use_docs=True) or root (if use_docs=False)

If mode="gh-actions"

  1. In Repo → Settings → Pages:
    • Build and deployment → Source: GitHub Actions.
Warning

Make sure you enable this before committing the files!

If you do not, it will not trigger a build when first enabled without you forcibly making a change to index.html and committing/pushing that change.

  1. Commit the generated files:
    • .github/workflows/deploy.yml
    • .nojekyll
    • 404.html
    • index.html in your target folder (docs/ if use_docs=True, else repo root).
  2. Push to your repo. The workflow will build and deploy your site.

Both

Your app will be available at:

https://<your-github-username>.github.io/<your-repo-name>/

Note: It can take a few minutes for the first deployment to appear. If using Actions, ensure the workflow runs and passes; if using manual mode, double-check your Pages settings.

Next Steps

  • Experiment with adding extra files (e.g., a .streamlit/config.toml for customization).
  • Share your packaged app on GitHub Pages.
  • Contribute back by reporting issues or suggesting improvements!