Python apps

Deploy a Streamlit, Gradio or FastAPI app only your team can open

Updated

Run jiayang deploy in the app's folder. It detects Streamlit, Gradio, FastAPI, Flask or Django, builds a container and puts it behind sign-in, so only the people you share it with can open it, with no login code in your app. Container apps need the Team plan or above.

What you need

Deploy it

In the app's folder:

jiayang deploy acme/report . --create

The first lines say what it found and how the app will start. Shortened, it looks like this:

a container (Streamlit)
  because it has requirements.txt, runs as a python container
  start: streamlit run app.py --server.port $PORT --server.address 0.0.0.0 --server.headless true
  python: 3.13
Building . for linux/amd64 ...
Image uploaded. Waiting for it to go live ...
It listens on port 8080 and runs at size basic.
Version 1 (7c3a91e0d5f2) is live.
https://report--acme.jiayang-apps.cloud

With no Dockerfile of yours, the deploy writes one: Python 3.13 unless .python-version or runtime.txt asks for 3.11 or 3.12, installed with uv, Poetry or pip from your lock file, requirements.txt or pyproject.toml. jiayang dockerfile prints it. The start command comes from what the project depends on:

Depends onStarts with
streamlitstreamlit run app.py, or main.py or streamlit_app.py
gradiopython app.py
fastapiuvicorn main:app
djangogunicorn <project>.wsgi:application
flaskgunicorn app:app

Set your own in jiayang.json as container.start. See Containers and How deploy decides what to build. To start from nothing, jiayang init fastapi writes a FastAPI app that already checks who is calling.

Share it

jiayang share acme/report sam@example.com
jiayang share acme/report @example.com

The first lets one person in, and the second everyone at your company's domain. People sign in with a code sent to their address, or with Google or Microsoft, and don't need an account first. Remove someone and they lose access within 60 seconds, open connections included.

Know who's using it

Every request reaches your app with a signed token saying who is calling. The jiayang package checks it, with an extra for each framework:

pip install "jiayang[streamlit]"    # or [gradio], [fastapi], [flask], [django]

Streamlit

import streamlit as st
from jiayang.streamlit import get_user

user = get_user()
if user is None:
    st.error("sign in to use this")
    st.stop()
st.write(f"hello {user.email}")

The caller is checked once per session. On Jiayang Cloud the edge closes the connection within a minute of someone's access being removed, and the session ends with it.

Gradio

import os

import gradio as gr
from jiayang.gradio import require_user

def answer(question, request: gr.Request):
    user = require_user(request)
    return f"{user.email} asked: {question}"

gr.Interface(answer, "textbox", "textbox").launch(
    server_name="0.0.0.0", server_port=int(os.environ.get("PORT", "7860"))
)

The app has to listen on 0.0.0.0 at the port in PORT. Gradio's defaults can't be reached here.

FastAPI

from jiayang.fastapi import CurrentUser

@app.get("/")
async def index(user: CurrentUser):
    return {"hello": user.email}

A request without a valid caller gets a 401 and never reaches your handler. requires("editor") asks for a role too. Flask and Django have the same in jiayang.flask and jiayang.django. See Verify the caller in a Python app.

jiayang dev runs any of these on your computer behind a copy of our sign-in, with real tokens, so you can try each role before you deploy.

Why not a share link or a password?

Gradio's share=True link is public: anyone who has it can use the app, and it lasts a week (Gradio's guide). A shared password gets passed around, and tells the app nothing about who is using it. Here each person signs in as themselves, you can take one person's access away without changing anything for the rest, and every visit is in the audit log with their name.

Streamlit Community Cloud allows one private app at a time, with viewers invited by email who sign in with Google or a single-use emailed link (Streamlit's docs). If that covers you, it's a fine choice. Jiayang Cloud is for more than one private app, sharing with a whole domain, and an audit log.

Questions

Is there a free option?

Not for Python servers. Free runs JavaScript, TypeScript and static apps only, and a container deploy on Free stops before it builds anything, with a message that says so.

What does the first request get while the container starts?

A 503 that says the app is starting. A browser gets a page with the same message, which reloads itself until the app answers. After an app's first deploy this can take several minutes. A container stops after 10 minutes with no requests and starts again on the next one.

Where does my data go between restarts?

Not on the container's disk, which goes back to what the image holds each time the container starts. Keep it in the app's database or files, or a Postgres database you connect.

How do I keep an API key out of the code?

Store it as a secret for the API's host with jiayang secret set. Our outbound proxy adds it to the app's requests to that host, so the code calls the API without it. See Secrets.

Sources

  1. Sharing your app, Gradio's guide. Checked 16 October 2026.
  2. Share your app, Streamlit's docs. Checked 16 October 2026.

Next