Main concepts

Working with Streamlit is simple. First you sprinkle a few Streamlit commands into a normal Python script, then you run it with streamlit run:

$ streamlit run [-- script args]

As soon as you run the script as shown above, a local Streamlit server will spin up and your app will open in a new tab your default web browser. The app is your canvas, where you’ll draw charts, text, widgets, tables, and more.

What gets drawn in the app is up to you. For example st.text writes raw text to your app, and st.line_chart draws — you guessed it — a line chart. Refer to our API documentation to see all commands that are available to you.


When passing your script some custom arguments, they must be passed after two dashes. Otherwise the arguments get interpreted as arguments to Streamlit itself.


You can also pass a URL to streamlit run! This is great when combined with Github Gists. For example:

$ streamlit run

Development flow

Every time you want to update your app, just save the source file. When you do that, Streamlit detects if there is a change and asks you whether you want to rerun your app. Choose “Always rerun” at the top-right of your screen to automatically update your app every time you change its source code.

This allows you to work in a fast interactive loop: you type some code, save it, try it out live, then type some more code, save it, try it out, and so on until you’re happy with the results. This tight loop between coding and viewing results live is one of the ways Streamlit makes your life easier.


While developing a Streamlit app, it’s recommended to lay out your editor and browser windows side by side, so the code and the app can be seen at the same time. Give it a try!

Data flow

Streamlit’s architecture allows you to write apps the same way you write plain Python scripts. To unlock this, Streamlit apps have a unique data flow: any time something must be updated on the screen, Streamlit just reruns your entire Python script from top to bottom.

This can happen in two situations:

  • Whenever you modify your app’s source code.

  • Whenever a user interacts with widgets in the app. For example, when dragging a slider, entering text in an input box, or clicking a button.

And to make all of this fast and seamless, Streamlit does some heavy lifting for you behind the scenes. A big player in this story is the @st.cache decorator, which allows developers to skip certain costly computations when their apps rerun. We’ll cover caching later in this page.

Drawing content

Writing to Streamlit apps is simple. Just call the appropriate API command:

import streamlit as st
x = 4
st.write(x, 'squared is', x * x)

In the example above we used the st.write() command. Whenever you want to draw something to the screen st.write() is always a good first start! It tries to guess the best visual representation for its arguments based on their data types, so things like dataframes are drawn as beautiful tables, Matplotlib figures are drawn as charts, and so on.

And you can even use Streamlit magic to skip the st.write() command altogether:

import streamlit as st
x = 4
x, 'squared is', x * x  # 👈 Magic!

If you want to do something more advanced like changing specific settings, drawing animations, or inserting content out of order, check out other available Streamlit commands in our API documentation and Advanced Concepts pages.


When you’ve got the data or model into the state that you want to explore, you can add in widgets like st.slider(), st.button() or st.selectbox(). It’s really straightforward — just treat widgets as variables:

import streamlit as st
x = st.slider('x')  # 👈 this is a widget
st.write(x, 'squared is', x * x)

On first run, the app above should output the text “0 squared is 0”. Then every time a user interacts with a widget, Streamlit simply reruns your script from top to bottom, assigning the current state of the widget to your variable in the process.

For example, if the user moves the slider to position 10, Streamlit will rerun the code above and set x to 10 accordingly. So now you should see the text “10 squared is 100”.


The Streamlit cache allows your app to execute quickly even when loading data from the web, manipulating large datasets, or performing expensive computations.

To use the cache, just wrap functions in the @st.cache decorator:

@st.cache  # 👈 This function will be cached
def my_slow_function(arg1, arg2):
    # Do something really slow in here!
    return the_output

When you mark a function with the @st.cache decorator, it tells Streamlit that whenever the function is called it needs to check a few things:

  1. The input parameters that you called the function with

  2. The value of any external variable used in the function

  3. The body of the function

  4. The body of any function used inside the cached function

If this is the first time Streamlit has seen these four components with these exact values and in this exact combination and order, it runs the function and stores the result in a local cache. Then, next time the cached function is called, if none of these components changed, Streamlit will just skip executing the function altogether and, instead, return the output previously stored in the cache.

For more information about the Streamlit cache, its configuration parameters, and its limitations, see Caching.

App model

Now that you know a little more about all the individual pieces, let’s close the loop and review how it works together:

  1. Streamlit apps are Python scripts that run from top to bottom

  2. Every time a user opens a browser tab pointing to your app, the script is re-executed

  3. As the script executes, Streamlit draws its output live in a browser

  4. Scripts use the Streamlit cache to avoid recomputing expensive functions, so updates happen very fast

  5. Every time a user interacts with a widget, your script is re-executed and the output value of that widget is set to the new value during that run.


Next steps