Reflex makes it simple to add file upload functionality to your app. You can let users select files, store them on your server, and display or process them as needed. Below is a minimal example that demonstrates how to upload files, save them to disk, and display uploaded images using application state.

You can let users upload files and keep track of them in your app’s state. The example below allows users to upload files, saves them using the backend, and then displays the uploaded files as images.

Selecting a file will add it to the browser file list, which can be rendered on the frontend using the rx.selected_files(id) special Var. To clear the selected files, you can use another special Var rx.clear_selected_files(id) as an event handler.

To upload the file(s), you need to bind an event handler and pass the special rx.upload_files(upload_id=id) event arg to it.

Reflex provides two key functions for handling uploaded files:

rx.get_upload_dir()

  • Purpose: Returns a Path object pointing to the server-side directory where uploaded files should be saved
  • Usage: Used in backend event handlers to determine where to save uploaded files
  • Default Location: ./uploaded_files (can be customized via REFLEX_UPLOADED_FILES_DIR environment variable)
  • Type: Returns pathlib.Path

rx.get_upload_url(filename)

  • Purpose: Returns the URL string that can be used in frontend components to access uploaded files
  • Usage: Used in frontend components (like rx.image, rx.video) to display uploaded files
  • URL Format: /_upload/filename
  • Type: Returns str

Key Differences

  • rx.get_upload_dir() -> Backend file path for saving files
  • rx.get_upload_url() -> Frontend URL for displaying files

Here is the standard pattern for handling file uploads:

Below is an example of how to allow multiple file uploads (in this case images).

Below is an example of how to allow only a single file upload and render (in this case a video).

In the example below, the upload component accepts a maximum number of 5 files of specific types. It also disables the use of the space or enter key in uploading files.

To use a one-step upload, bind the event handler to the rx.upload component's on_drop trigger.

To use a completely unstyled upload component and apply your own customization, use rx.upload.root instead:

Your event handler should be an async function that accepts a single argument, files: list[UploadFile], which will contain FastAPI UploadFile instances. You can read the files and save them anywhere as shown in the example.

In your UI, you can bind the event handler to a trigger, such as a button on_click event or upload on_drop event, and pass in the files using rx.upload_files().

By convention, Reflex provides the function rx.get_upload_dir() to get the directory where uploaded files may be saved. The upload dir comes from the environment variable REFLEX_UPLOADED_FILES_DIR, or ./uploaded_files if not specified.

The backend of your app will mount this uploaded files directory on /_upload without restriction. Any files uploaded via this mechanism will automatically be publicly accessible. To get the URL for a file inside the upload dir, use the rx.get_upload_url(filename) function in a frontend component.

When using the Reflex hosting service, the uploaded files directory is not persistent and will be cleared on every deployment. For persistent storage of uploaded files, it is recommended to use an external service, such as S3.

By default, Reflex creates the following structure:

The files are automatically served at:

  • /_upload/image1.pngrx.get_upload_url("image1.png")
  • /_upload/document.pdfrx.get_upload_url("document.pdf")
  • /_upload/video.mp4rx.get_upload_url("video.mp4")

The id provided to the rx.upload component can be passed to the special event handler rx.cancel_upload(id) to stop uploading on demand. Cancellation can be triggered directly by a frontend event trigger, or it can be returned from a backend event handler.

The rx.upload_files special event arg also accepts an on_upload_progress event trigger which will be fired about every second during the upload operation to report the progress of the upload. This can be used to update a progress bar or other UI elements to show the user the progress of the upload.

The progress dictionary contains the following keys:

API Reference

rx.upload

The styled Upload Component.

PropType | ValuesDefault
accept
Union[dict, NoneType]
disabled
bool
max_files
int
max_size
int
min_size
int
multiple
bool
no_click
bool
no_drag
bool
no_keyboard
bool
drag_active_style
Union[Style, NoneType]
None

Event Triggers

See the full list of default event triggers
TriggerDescription
on_drop Marked True when any Upload component is created. Fired when files are dropped.

rx.upload.root

A file upload component.

PropType | ValuesDefault
accept
Union[dict, NoneType]
disabled
bool
max_files
int
max_size
int
min_size
int
multiple
bool
no_click
bool
no_drag
bool
no_keyboard
bool
drag_active_style
Union[Style, NoneType]
None

Event Triggers

See the full list of default event triggers
TriggerDescription
on_drop Marked True when any Upload component is created. Fired when files are dropped.

Built with Reflex