After Upload file stays in RAM

Please take a moment to search the forum and documentation before posting a new topic.
If you’re creating a debugging post, please include the following info:

  1. Are you running your app locally or is it deployed? local

Streamlit Version 1.49.1
Python Version 3.13.7

I searched for the issue on all known databases without success :frowning:

I am facing the following issue with st.file_uploader:

When I am uploading a File about 600MB the RAM usage is after I selected the File about 660 MB.
At the moment I pressed the upload button the RAM usage increases up to 1800MB.
After the Upload is done, the RAM usage stays at 660MB.
If I close the browsertab it stays at 660MB, only when I close the streamlit instance the RAM gets free.

I tryed several solutions:

  • clear_on_submit=True
  • working with session state keys
  • gc.collect()
  • st.rerun()

The phenomenon is:
If I set the clear_on_submit=false and deactivate the st.rerun() I am able to delete the File in the Widget and only then the file gets deleted from the RAM.

I tested it with a simple Upload code with the same result.

Actually I have no idea how to fix this, can somebody help?

here my Upload Code:
-------- Upload-Helper --------

def save_uploaded_file(file, folder):
os.makedirs(folder, exist_ok=True)
save_path = os.path.join(folder, file.name)

with open(save_path, "wb") as f:
    shutil.copyfileobj(file, f)

return save_path

def unified_upload(device_id):
st.subheader(“:open_file_folder: Dokument hochladen”)

# Dokumenttypen + erlaubte Dateiendungen
doc_types = {
    "Firmware": {"label": "💾 Firmware", "allowed_types": ["zip", "pdf"]},
    "Manual": {"label": "📘 Servicemanual", "allowed_types": ["pdf"]},
    "Partslist": {"label": "🛠️ Partslist", "allowed_types": ["pdf"]},
    "Bulletin": {"label": "📑 Bulletin", "allowed_types": ["pdf"]},
}

# Upload-Counter initialisieren
if "upload_counter" not in st.session_state:
    st.session_state.upload_counter = {}

if device_id not in st.session_state.upload_counter:
    st.session_state.upload_counter[device_id] = 0

# Dropdown zur Auswahl des Dokumententyps
doc_choice = st.selectbox(
    "Dokumenttyp auswählen",
    options=list(doc_types.keys()),
    format_func=lambda x: doc_types[x]["label"],
    index=None,
    placeholder="Bitte auswählen...",
    key=f"doc_select_{device_id}"
)

if not doc_choice:
    st.info("Bitte zuerst den Dokumenttyp auswählen ⬆️")
    return

# Zielordner für Gerät & Typ
folder = os.path.join(r"D:\ServiceInfoToolData", str(device_id), doc_choice)
os.makedirs(folder, exist_ok=True)

# Dynamischen Key für file_uploader
file_key = f"file_upload_{device_id}_{doc_choice}_{st.session_state.upload_counter[device_id]}"

# Upload-Formular mit Auto-Reset
with st.form(f"upload_form_{device_id}_{doc_choice}", clear_on_submit=True):
    file = st.file_uploader(
        f"{doc_types[doc_choice]['label']} hochladen",
        type=doc_types[doc_choice]["allowed_types"],
        key=file_key
    )

    title = st.text_input("Titel (optional)")
    submitted = st.form_submit_button("Speichern")

    if submitted:
        if file is None:
            st.error("Bitte eine Datei auswählen.")
        else:
            save_path = save_uploaded_file(file, folder)

            # DB-Eintrag speichern
            conn = get_connection()
            try:
                conn.execute(
                    """
                    INSERT INTO serviceinfos 
                    (geraet_id, typ, dateiname, pfad, uploaded_at, version) 
                    VALUES (?,?,?,?,?,?)
                    """,
                    (
                        device_id,
                        doc_choice,
                        file.name,
                        save_path,
                        datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                        title.strip() or None,
                    ),
                )
                conn.commit()
            finally:
                conn.close()

            # Upload-Counter hochzählen, damit nächster Upload einen neuen Key bekommt
            st.session_state.upload_counter[device_id] += 1

            # Speicher freigeben
            del file
            st.session_state._uploaded_file_mgr = UploadedFileManager()
            gc.collect()
            st.rerun()

            st.success(f"{doc_types[doc_choice]['label']} hochgeladen ✅")

This cant be real… only by uploading an 800MB File with Streamlit 4 Times, nobody here with an idea how to solve this?
Actually the RAM gets free when I close the Browsertab.
Thats a little hope.

When you use st.file_uploader, the file does indeed stay in memory. If you want the file to be saved on disk, you’ll have to do that yourself. And yes, this information in memory will clear when the session ends (when the tab is closed).

Are you saying the the uploaded files are staying in memory after they are cleared from the widget, like a memory leak?

Yes it stays in RAM after the Upload is done and the Session is cleared.

  1. file choose
  2. Upload
  3. Session clear via changing Session keys, clear_on_submit=true etc.

Result: File stays in RAM.

The only way to delete the file from RAM is to set clear_on_submit=false and delete the file manually from the Widget by pressing the x for removing the file.

I tried this on 2 PCs with several browsers.

I have no solution for this issue.

Please can you open a GitHub issue for our devs to investigate this.

Done: After File Upload the file stays in RAM · Issue #12607 · streamlit/streamlit · GitHub

Same issue with Streamlit 1.50

1 Like