Mounting new starlette ASGI app inside Litestar

Hello,

I’m trying to mount Streamlit in a Litestar app using the new starlette ASGI server that just came out with 1.53. I know this is very new, experimental and only documented with fastAPI but I figured I might as well try and I’m not that far.

I’m trying locally and I created a small example app here: GitHub - iv-nn/streamlit-starlette-test (don’t mind the devenv related files). I used this comment and the litestar example a source.

It has a minimal Streamlit dashboard and 2 apps. A FastApi one in fastapp.py and a Litestar one in liteapp.py.

If I start the FastApi one with uv run uvicorn fastapp:app and go to /dashboard everything works.

If I start the Litestar one with uv run uvicorn liteapp:app and go to /dashboard I get a white page and some 404s while trying to load assets.
The issue is that requests to assets (like /dashboard/static/js/index.DSTThs-t.js) receive a 301 response and are redirected to /static/js/index.DSTThs-t.js. I guess that’s because Streamlit is not aware that’s it’s server under /dashboard but I’m not sure how to configure that.

The FastApi doc mention a root_path parameter from the ASGI spec but my understanding is that it should be already passed in the scope.

I’m really not sure if the issue is with one or the other app, or more probably a misconfiguration on my side as I don’t know this matter very well. So I’m posting in both forum, sorry if it’s unrelated.

Welcome to the community and thanks for sharing your question and repo! :rocket: You’re right—mounting Streamlit as an ASGI app under a subpath (like /dashboard) is very new and only officially documented for FastAPI so far. The issue you’re seeing (Streamlit asset requests being redirected from /dashboard/static/... to /static/..., resulting in 404s) is because Streamlit’s ASGI app isn’t aware it’s mounted under a subpath, so it generates asset URLs relative to /, not /dashboard/.

According to the experimental ASGI app PR and the FastAPI example, Streamlit’s ASGI app should respect the root_path in the ASGI scope, which is set automatically by FastAPI when mounting. If Litestar doesn’t set the root_path in the ASGI scope when mounting, Streamlit won’t know it’s under /dashboard, causing exactly the behavior you describe. This is a Litestar integration detail, not a Streamlit config option. You may need to check Litestar’s documentation or issue tracker to confirm if it sets root_path correctly when mounting sub-apps, or if you need to set it manually.

If you want to experiment, you could try manually setting the root_path in the ASGI scope when mounting the Streamlit app in Litestar, similar to how it’s done in FastAPI. But as of now, Streamlit’s ASGI app does not provide a direct config or parameter to override the base path—it’s fully dependent on the ASGI root_path mechanism. This is not a Streamlit config option, and there is no documented workaround in the official docs for this scenario. For reference, see the ASGI app PR discussion and FastAPI mounting example.

Sources:

I found a solution, from Litestar the proper way to mount Streamlit is as follow:

from litestar import Litestar, asgi
from streamlit.starlette import App

streamlit_app = App(“src/dashboard.py”)
streamlit = asgi(path=“/dashboard/”, is_static=True, copy_scope=True)(streamlit_app)

app = Litestar(route_handlers=[streamlit], lifespan=[streamlit_app.lifespan()])

You need to use is_static=True instead of is_mount=True.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.