Streamlit Supabase Connector
A Streamlit connection component to connect Streamlit to Supabase Storage and Database.
Explore the connector in the demo app (no Supabase account needed):
Why use this?
-
Cache functionality to cache returned results. Save time and money on your API requests
-
Same method names as the Supabase Python API. Minimum relearning required
-
Exposes more storage methods than currently supported by the Supabase Python API. For example,
update()
,create_signed_upload_url()
, andupload_to_signed_url()
-
Less keystrokes required when integrating with your Streamlit app.
Examples with and without the connector
Without connector With connector Download file to local system from Supabase storage import mimetypes import streamlit as st from supabase import create_client supabase_client = create_client( supabase_url="...", supabase_key="..." ) bucket_id = st.text_input("Enter the bucket_id") source_path = st.text_input("Enter source path") file_name = source_path.split("/")[-1] if st.button("Request download"): with open(file_name, "wb+") as f: response = supabase_client.storage.from_(bucket_id).download(source_path) f.write(response) mime = mimetypes.guess_type(file_name)[0] data = open(file_name, "rb") st.download_button("Download file", data=data, file_name=file_name, mime=mime)
import streamlit as st from st_supabase_connection import SupabaseConnection st_supabase_client = st.experimental_connection( name="supabase_connection", type=SupabaseConnection ) bucket_id = st.text_input("Enter the bucket_id") source_path = st.text_input("Enter source path") if st.button("Request download"): file_name, mime, data = st_supabase_client.download(bucket_id, source_path) st.download_button("Download file", data=data, file_name=file_name, mime=mime)
Upload file from local system to Supabase storage import streamlit as st from supabase import create_client supabase_client = create_client( supabase_key="...", supabase_url="..." ) bucket_id = st.text_input("Enter the bucket_id") uploaded_file = st.file_uploader("Choose a file") destination_path = st.text_input("Enter destination path") overwrite = "true" if st.checkbox("Overwrite if exists?") else "false" with open(uploaded_file.name, "wb") as f: f.write(uploaded_file.getbuffer()) if st.button("Upload"): with open(uploaded_file.name, "rb") as f: supabase_client.storage.from_(bucket_id).upload( path=destination_path, file=f, file_options={ "content-type": uploaded_file.type, "x-upsert": overwrite, }, )
import streamlit as st from st_supabase_connection import SupabaseConnection st_supabase_client = st.experimental_connection( name="supabase_connection", type=SupabaseConnection ) bucket_id = st.text_input("Enter the bucket_id") uploaded_file = st.file_uploader("Choose a file"): destination_path = st.text_input("Enter destination path") overwrite = "true" if st.checkbox("Overwrite if exists?") else "false" if st.button("Upload"): st_supabase_client.upload( bucket_id, "local", uploaded_file, destination_path, overwrite, )
Setup
- Install
st-supabase-connection
pip install st-supabase-connection
- Set the
SUPABASE_URL
andSUPABASE_KEY
Streamlit secrets as described here.
[!NOTE]
For local development outside Streamlit, you can also set these as your environment variables (recommended), or pass these to theurl
andkey
args ofst.experimental_connection()
(not recommended).
Usage
- Import
from st_supabase_connection import SupabaseConnection
- Initialize
st_supabase_client = st.experimental_connection(
name="YOUR_CONNECTION_NAME",
type=SupabaseConnection,
ttl=None,
url="YOUR_SUPABASE_URL", # not needed if provided as a streamlit secret
key="YOUR_SUPABASE_KEY", # not needed if provided as a streamlit secret
)
- Use in your app to query tables and files. Happy Streamlit-ing!
Supported methods
Storage
- delete_bucket()
- empty_bucket()
- get_bucket()
- list_buckets()
- create_bucket()
- upload()
- download()
- update_bucket()
- move()
- list_objects()
- create_signed_urls()
- get_public_url()
- create_signed_upload_url()
- upload_to_signed_url()
Database
- query() - Runs a cached SELECT query
- All methods supported by postgrest-py.
Examples
Storage operations
List existing buckets
>>> st_supabase.list_buckets(ttl=None)
[
SyncBucket(
id="bucket1",
name="bucket1",
owner="",
public=False,
created_at=datetime.datetime(2023, 7, 31, 19, 56, 21, 518438, tzinfo=tzutc()),
updated_at=datetime.datetime(2023, 7, 31, 19, 56, 21, 518438, tzinfo=tzutc()),
file_size_limit=None,
allowed_mime_types=None,
),
SyncBucket(
id="bucket2",
name="bucket2",
owner="",
public=True,
created_at=datetime.datetime(2023, 7, 31, 19, 56, 28, 203536, tzinfo=tzutc()),
updated_at=datetime.datetime(2023, 7, 31, 19, 56, 28, 203536, tzinfo=tzutc()),
file_size_limit=100,
allowed_mime_types=["image/jpg", "image/png"],
),
]
Create a bucket
>>> st_supabase_client.create_bucket("new_bucket")
{'name': 'new_bucket'}
Get bucket details
>>> st_supabase.get_bucket("new_bucket")
SyncBucket(id='new_bucket', name='new_bucket', owner='', public=True, created_at=datetime.datetime(2023, 8, 2, 19, 41, 44, 810000, tzinfo=tzutc()), updated_at=datetime.datetime(2023, 8, 2, 19, 41, 44, 810000, tzinfo=tzutc()), file_size_limit=None, allowed_mime_types=None)
Update a bucket
>>> st_supabase_client.update_bucket(
"new_bucket",
file_size_limit=100,
allowed_mime_types=["image/jpg", "image/png"],
public=True,
)
{'message': 'Successfully updated'}
Move files in a bucket
>>> st_supabase_client.move("new_bucket", "test.png", "folder1/new_test.png")
{'message': 'Successfully moved'}
List objects in a bucket
>>> st_supabase_client.list_objects("new_bucket", path="folder1", ttl=0)
[
{
"name": "new_test.png",
"id": "e506920e-2834-440e-85f1-1d5476927582",
"updated_at": "2023-08-02T19:53:22.53986+00:00",
"created_at": "2023-08-02T19:52:20.404391+00:00",
"last_accessed_at": "2023-08-02T19:53:21.833+00:00",
"metadata": {
"eTag": '"814a0034f5549e957ee61360d87457e5"',
"size": 473831,
"mimetype": "image/png",
"cacheControl": "max-age=3600",
"lastModified": "2023-08-02T19:53:23.000Z",
"contentLength": 473831,
"httpStatusCode": 200,
},
}
]
Empty a bucket
>>> st_supabase.empty_bucket("new_bucket")
{'message': 'Successfully emptied'}
Delete a bucket
>>> st_supabase_client.delete_bucket("new_bucket")
{'message': 'Successfully deleted'}
Database operations
Simple query
>>> st_supabase.query("*", table="countries", ttl=0).execute()
APIResponse(
data=[
{"id": 1, "name": "Afghanistan"},
{"id": 2, "name": "Albania"},
{"id": 3, "name": "Algeria"},
],
count=None,
)
Query with join
>>> st_supabase.query("name, teams(name)", table="users", count="exact", ttl="1h").execute()
APIResponse(
data=[
{"name": "Kiran", "teams": [{"name": "Green"}, {"name": "Blue"}]},
{"name": "Evan", "teams": [{"name": "Blue"}]},
],
count=None,
)
Filter through foreign tables
>>> st_supabase.query("name, countries(*)", count="exact", table="cities", ttl=None).eq(
"countries.name", "Curaçao"
).execute()
APIResponse(
data=[
{
"name": "Kralendijk",
"countries": {
"id": 2,
"name": "Curaçao",
"iso2": "CW",
"iso3": "CUW",
"local_name": None,
"continent": None,
},
},
{"name": "Willemstad", "countries": None},
],
count=2,
)
Insert rows
>>> st_supabase_client.table("countries").insert(
[{"name": "Wakanda", "iso2": "WK"}, {"name": "Wadiya", "iso2": "WD"}], count="None"
).execute()
APIResponse(
data=[
{
"id": 250,
"name": "Wakanda",
"iso2": "WK",
"iso3": None,
"local_name": None,
"continent": None,
},
{
"id": 251,
"name": "Wadiya",
"iso2": "WD",
"iso3": None,
"local_name": None,
"continent": None,
},
],
count=None,
)
[!NOTE]
Check the Supabase Python API reference for more examples.
Explore all options in a demo app
Acknowledgements
This connector builds upon the awesome work done by the open-source community in general and the Supabase Community in particular. I cannot be more thankful to all the authors whose work I have used either directly or indirectly.