Using PyInstaller (or similar) to create an executable

Hi, I want to build a one-click executable out of my code that replicates the terminal command:

streamlit run

Is there any way to achieve this with PyInstaller or similar? The main motivation is to share the functionality of my app with others who only use windows or who only use computers where python (along with the required imports) is not installed.

1 Like

Hi @s_mc and welcome to the forum! :wave:

The best way to share would be to run streamlit in a server and share the app url. Another option would be to create a docker image with your code and share the image, but this docker option could be a little complex for individuals who are using your app.

Currently, we don’t have a way to internally deploy your app within Streamlit, but we are working on a “For Teams” offering that will add this functionality. If you’re interested in hearing more, here is a link where you can sign-up to get updates as they become available.

In the meantime, here is a link to a post that goes over some community driven ways to host your app.

Hope this helps answer your question, and feel free to let us know if this isn’t the functionality you’re looking for! :smiley:

UPDATE Not yet solved, but almost, further help appreciated!!!

I created the following wrapper script to allow any script utilitzing streamlit to be run by calling

import runpy
import streamlit.cli
import click
if __name__ == '__main__':
    streamlit.cli._main_run_clExplicit('', 'streamlit run')

Save the 7 lines above into another script called (or any other name). You will also need to edit the file contained in the streamlit distribution to include the following def:

def _main_run_clExplicit(file, command_line, args=[]):
    streamlit._is_running_with_streamlit = True
    if version.should_show_new_version_notice():
        click.echo(NEW_VERSION_TEXT), command_line, args)

After all that, you can run your script using the usual python call python

The next step is to run:


And with some massaging you should receive an executable.

The problem now is, the pyinstaller executable starts streamlit on port 3000 instead of port 8501 and my browser (for reasons I don’t understand) can’t run my script when using streamlitWrapper.exe (this is the default name of the executable pyinstaller will produce), running python works exactly the same as when calling streamlit run, but for some reason the pyinstaller executable doesn’t exactly replicate the functionality you get when running python


I have discovered the reason why when using the bundled executable my web browser doesn’t load properly, it is due to a check performed in streamlit to establish whether streamlit was properly installed. Basically everytime streamlit is run, at some time the following is executed in

@_create_option("global.developmentMode", visibility="hidden", type_=bool)
    def _global_development_mode():
        """Are we in development mode.

        This option defaults to True if and only if Streamlit wasn't installed
        return (
            not util.is_pex()
            and "site-packages" not in __file__
            and "dist-packages" not in __file__

This is called from which has the effect of setting the port to 3000:

def _get_browser_address_bar_port():
    """Get the report URL that will be shown in the browser's address bar.

    That is, this is the port where static assets will be served from. In dev,
    this is different from the URL that will be used to connect to the
    server-browser websocket.

    if config.get_option("global.developmentMode") and config.get_option(
        return 3000
    return config.get_option("browser.serverPort")

This call works normally when using either streamlit run or python but (for whatever reason), once pyinstaller bundles streamlit into the executable, the above check fails and sends streamlit into development mode, and things stop working as expected. This is obviously the wrong behaviour on streamlit’s part, pyinstaller has almost certainly bundled everything correctly but streamlit is looking in the wrong place to check if it has been installed correctly. What do I need to modify to ensure that streamlit is satisfied that it has been properly installed when running from an executable? I get the feeling that modifying def _global_development_mode(): to always return True is probably a dangerous idea.


Wow, great detective work @s_mc!

I think there’s some work Streamlit devs can do to make this easier in the future, but for now it sounds like all that’s left for you is to turn global.developmentMode off — which happens to be quite simple :smiley:

Here are a few ways to do it:

  • Add the code below to either $HOME/.streamlit/config.toml or .streamlit/config.toml (in the folder you’re running Streamlit from)

    developmentMode = false
  • Pass --global.developmentMode=false to the streamlit run command

  • Set the STREAMLIT_GLOBAL_DEVELOPMENT_MODE environment variable to false

Let me know how it goes!

Team, any luck here? I’m really waiting for an easy pyinstaller functionality for streamlit!

I didn’t pursue this further, my solution was to run my streamlit program on a VM. When the VM boots it starts a service that runs my streamlit program. I would still prefer a pyinstaller compatible version of streamlit though.

1 Like

The StreamlitWrapper script did not start streamlit for the current version. Also, Credentials object now has ._check_activated (instead of .check_activated) attribute. Running:
python did not start streamlit, the script ran without throwing any exception but nothing happened.
Really looking forward to the Teams version which will allow packaging of streamlit app into single executable file for distribution - I know there’s a separate thread about bundling Streamlit + Electron as well here. Fingers crossed either of these will be implemented by Streamlit dev.

Commenting out the line “if version.should_show_new_version_notice():” in _main_run_clExplicit seems to make it work.

can anyone sum up the entire process if you have figured it out? Thanks!

1 Like

By having this function run as the main function of the compiled script, I’m able to get streamlit to try to start the webapp under pyinstaller.

def streamlit_run():
    this_dir = Path(__file__).parent
    sys.argv = ["streamlit", "run", "", "--global.developmentMode=false"]

I changed the spec file (from pyinstaller) so that it could find the import for (by specifying to copy over the script).

Although streamlit starts up the local server (usual output with You can view your Streamlit app... and on port 8501), it gives a 404: Not Found error on actually loading the webpage.
This is as far as I’ve managed to get.

Hi david,

Can you explain how this is done. Maybe include your code in larger example. How are you aming use of this function that you have created?

[Note This still doesn’t work]

I created an example project like so:

    - env.yml

The env.yml is for the conda environment: [I also checked with a virtualenv environment, and had the exact same problem]

name: streamlit-build-test
  - defaults
  - python=3.6
  - pip
  - pip:
      - streamlit is:

import streamlit as st
if __name__ == '__main__':
    x = st.text('foo')

Pyinstaller couldn’t find streamlit on its own, so I had to add

from PyInstaller.utils.hooks import copy_metadata
datas = copy_metadata('streamlit')

And then is a wrapper for the app, that essentially calls streamlit run

import sys
import streamlit.cli as stcli

if __name__ == '__main__':
    sys.argv = ["streamlit", "run", "", "--global.developmentMode=false"]

Now, to compile the app, run:

$ pyinstaller --onefile --additional-hooks-dir=. -w

Then run the compiled app with:

$ dist/streamlit_run

The command line shows streamlit is running, but unfortunately the browser can’t seem to find the page (at the ip) on localhost, and gives a 404 not found error.

1 Like

Hello! I’ve been going through this forum looking for ways to share my streamlit app with colleagues. I have it on a virtual machine right now but I’m stuck on how to share the link from the virtual machine to non-technical coworkers. How did you go about doing it?

My Streamlit server runs on localhost of my VM (guest) on port 50000 (or whatever port you want), my VM is Linux so my localhost address is In my Virtualbox settings I have port forwarding enabled from guest to host. In my host (Windows) I had to enable firewall exceptions for port 50000, if I want other people to see my server, I simply share the network address of my host (for example 192.168.0.x) and the port (50000) and as long as the VM is running, people can see my streamlit app via their browser at the address: http://192.168.0.x:50000

Not sure if creating a batch file (as a one-click button) to open the environment
can do what you want…

(04:14 from the following video)

I Discovered a Way By which you can make an executable file without Pyinstaller
Just Click This Link And Read It I’ve Listed the Steps

1 Like

Dear all,

thanks a lot for meaningful discussion.
I was also faced with the same problem.

Now, I found a solution without 404 not found error.


  • python = 3.7.9
  • streamlit = 0.71.0
  • pyinstaller = 4.1

After that, suppose we want to make an executable file from the following


import streamlit as st

if __name__ == '__main__':
    st.header("Hello world")


  1. Wrap the main script.

    • Make a wrapper script
    • Add the following lines to contained in the streamlit distribution, e.g. ${YOUR_CONDA_ENV}/lib/site-packages/streamlit/


import streamlit.cli

if __name__ == '__main__':
    streamlit.cli._main_run_clExplicit('', 'streamlit run')


def _main_run_clExplicit(file, command_line, args=[ ]):
    streamlit._is_running_with_streamlit = True, command_line, args)
  1. Create ./hooks/


from PyInstaller.utils.hooks import copy_metadata
datas = copy_metadata('streamlit')
  1. Create ./.streamlit/config.toml:


developmentMode = false

port = 8501
  1. (NEW) Edit run_main.spec which is created after pyinstaller --onefile --additional-hooks-dir=./hooks --clean:


# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis([''],
pyz = PYZ(...)
exe = EXE(...)
  1. Finally, execute pyinstaller --onefile --additional-hooks-dir=./hooks run_main.spec --clean.


    - .streamlit/
        - config.toml
    - hooks/
    - run_main.spec
    - build/
        - run_main/
            - many .toc and .pyz
    - dist/
        - run_main.exe


The executable file created above does not work alone.
You should copy .streamlit and into dist direcoty.

Thank you :grinning:


I can confirm the method from @hmasdev.
This is awesome, thanks a lot!
It is even possible to edit the streamlit script ( in this case) during runtime as usual.

Nicely done!

Random (delusional?) thoughts…

Instead of making a streamlit binary for one app:

  • we could maybe create a generic streamlit runner that can execute any script passed in argument (or with a drag & drop onto the .exe)
  • and maybe associate an extension like / myapp.stpy so that it runs with that streamlit runner :smiley:
  • and maybe we could modify that specific version of streamlit to run in an electron app (cf. this issue)

There’s still the case of particular imports in your app, but we could imagine creating different streamlit runners which bundle commonly used libraries :smiley: