Skip to content
>GLB_
Go back

Deploying a Streamlit analytics app in one afternoon

Streamlit Community Cloud is the fastest path from a working local Streamlit app to a deployed URL. No Docker, no cloud provider setup, no billing configuration for small apps. Connect a GitHub repo, point it at your app.py, deploy.

Here’s the setup for a multipage analytics app backed by DuckDB, deployed in an afternoon.

What you need before deploying

The last point is where most deployments get stuck.

requirements.txt for this stack

streamlit==1.57.0
duckdb==1.10.0
pandas==2.2.3
plotly==5.24.1
scikit-learn==1.6.1
numpy==2.2.0

Pin versions. Streamlit Community Cloud installs from requirements.txt on every deploy. An unpinned dependency that gets a major version bump will break the app at deploy time rather than during development when you’d catch it.

Handling the DuckDB file

The synthetic dataset is small enough (DuckDB file is under 50MB) to commit directly to the repo.

git add tuva.duckdb
git commit -m "add DuckDB database file"
git push

On each deploy, Community Cloud checks out the repo and the .duckdb file is present at the expected path.

If your data is larger than ~100MB, the practical approach is to store it in S3 and download it at container startup:

# app.py — runs before any page renders
import os
import boto3

if not os.path.exists("tuva.duckdb"):
    s3 = boto3.client("s3")
    s3.download_file("your-bucket", "tuva.duckdb", "tuva.duckdb")

pg = st.navigation([...])
pg.run()

Community Cloud containers have ephemeral storage, so the file is rebuilt on every restart. For a dataset that changes daily, pair this with a scheduled rebuild.

Secrets for S3 credentials

If your app needs AWS credentials or API keys, use Streamlit’s secrets management rather than environment variables. In the Community Cloud dashboard, go to your app’s settings and add secrets in TOML format:

AWS_ACCESS_KEY_ID = "AKIA..."
AWS_SECRET_ACCESS_KEY = "..."

Access them in code:

import streamlit as st

key_id = st.secrets["AWS_ACCESS_KEY_ID"]
secret = st.secrets["AWS_SECRET_ACCESS_KEY"]

Locally, create .streamlit/secrets.toml in your project root with the same format. Add it to .gitignore.

The deploy steps

  1. Push all code and the .duckdb file to GitHub
  2. Go to share.streamlit.io and sign in with GitHub
  3. Click “New app” → select repo, branch, and main file path (app.py)
  4. Click “Deploy”

First deploy takes 3-5 minutes while Community Cloud installs the requirements.txt dependencies and starts the app. Subsequent deploys on the same repo pick up new pushes automatically if auto-deploy is enabled.

The app.py structure for deployment

import streamlit as st
import duckdb

st.set_page_config(
    page_title="Tuva Analytics",
    layout="wide",
)

@st.cache_resource
def get_db():
    return duckdb.connect("tuva.duckdb", read_only=True)

if "db" not in st.session_state:
    st.session_state.db = get_db()

pg = st.navigation([
    st.Page("tuva_explorer.py", title="Tuva Explorer"),
    st.Page("data_quality_explorer.py", title="Data Quality"),
    st.Page("predictions.py", title="Risk Predictions"),
])
pg.run()

st.set_page_config must be the first Streamlit call in app.py. Setting layout="wide" is worth it for data-heavy dashboards — it uses the full browser width instead of the centered narrow column default.

What the free tier gives you

Streamlit Community Cloud free tier:

For a demo or portfolio app reading from a committed DuckDB file, the free tier is enough. A DuckDB file under 50MB, four Python files, and requirements.txt deploys cleanly and stays live with no ongoing cost.


Share this post:

Related Posts


Previous Post
dbt + DuckDB: the good, the bad, and the workarounds
Next Post
DuckDB concurrency in 2026: why you can't run dbt and DBeaver at the same time