[시리즈] Streamlit 웹앱을 클라우드로 배포하기
Streamlit + Supabase로 내가 만든 웹앱을 배포해보자
- ▶ [Python] Streamlit - 파이썬으로 웹앱 만들기
- [Python] Streamlit 에서 JavaScript 사용하기
Streamlit 소개
1. Streamlit

A Faster way to build and share data apps
”데이터 앱을 더 빠르게 만들고 공유하는 방법”
Streamlit은 Python 코드만으로 데이터 앱, 대시보드, AI나 ML 데모 웹앱을 빠르게 만들 수 있게 도와주는 오픈소스 프레임워크이다. 이를 이용해 웹 개발 지식 없이도 Python 스크립트 몇 줄만으로 브라우저에서 실행되는 인터랙티브 앱을 만들 수 있다.
데이터 시각화, 대시보드, ML/AI 데모 웹앱 또는 내부 업무용 도구 등 간단한 웹앱을 만들기 굉장히 편한 도구이며, Streamlit Community Cloud를 통해 손쉽게 무료로 배포도 가능하다. 또한 Supabase와의 연동을 통해 DB도 사용할 수 있다.
이번 포스팅 시리즈에서는 Streamlit의 기본 사용법, 그리고 이를 배포하고, Supabase에 연결하는 방법을 알아보고 실제로 나만의 웹앱을 만들어보는 프로젝트를 진행해보도록 한다.
2. Streamlit으로 뭘 만들 수 있나?
이건 아래 Streamlit 앱 만들기 에서 하나씩 살펴보자
3. Streamlit의 장점
- 빠른 개발 속도
- 하나의 py 코드만으로도 만들 수 있는 웹앱 (물론 코드파일 분리도 가능)
- Pandas DataFrame 연동성 좋음
- 시각화(차트, 그래프, 표), 마크다운 사용가능, 채팅화면 등 데모 웹앱으로는 충분한 기능
4. 설치
Streamlit을 사용하려면 우선 설치부터 한다. 이를 위한 Python 은 기본적으로 설치되어있다는 것을 전제로 한다.
1
2
3
4
5
# uv
uv add streamlit
# pip
pip install streamlit
Streamlit 앱 만들기
Streamlit 홈페이지의 Playground 예제를 참고해 만든 기능들이다. 더 많은 기능들은 홈페이지 참고하기
1. blank
아무것도 없는 화면이다. 단지 streamlit을 import 하기만 했을 때이다.
1
2
# 01_blank.py
import streamlit as st
만든 앱을 실행할 때에는 streamlit run <파일이름> 으로 실행해준다. 만약 uv 를 사용한다면, 앞에 uv run 을 붙여줘야 한다.
1
2
3
4
5
# uv
uv run streamlit run 01_blank.py
# pip
streamlit run 01_blank.py
실행하면 터미널에 아래와 같이 실행로그와 함께 접속할 수 있는 URL이 표시된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
% uv run streamlit run 01_blank.py
2026-05-24 00:38:18.854 Uvicorn server started on 0.0.0.0:8501
You can now view your Streamlit app in your browser.
Local URL: http://localhost:8501
Network URL: http://XXX.XXX.XXX.XXX:8501
For better performance, install the Watchdog module:
$ xcode-select --install
$ pip install watchdog
인터넷 브라우저를 통해 해당 URL에 접속하거나, Ctrl을 누른 상태로 터미널창의 URL을 누르면 브라우저에서 만든 앱을 볼 수 있다. 물론 지금은 아무런 코드도 짜지 않았으므로, 아래처럼 Deploy와 우측 상단 메뉴를 제외하곤 빈 화면만 보일 것이다.

2. 마크다운
streamlit은 마크다운 문법을 표현할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 02_markdown.py
import streamlit as st
st.title("Ai there!👋")
content = """
## Intro
Jongya의 개발 블로그입니다.
세상의 다양한 문제들을 해결하는 개발자가 되고 싶습니다.
**:rainbow[Streamlit]** 은 마크다운 문법을 표함해 아래와 같은 컨텐츠를 표현할 수 있습니다.
| 기능 | 설명 |
| ------- | ----------------------------------- |
| 텍스트 출력 | 제목, 설명, Markdown 표시 |
| 데이터 표시 | DataFrame, 테이블, JSON 출력 |
| 차트 | 선 그래프, 막대 그래프, 지도, Plotly/Altair 연동 |
| 입력 위젯 | 버튼, 슬라이더, 체크박스, 파일 업로드 |
| 레이아웃 | 사이드바, 탭, 컬럼, 컨테이너 |
| 상태 관리 | 사용자의 입력 상태 저장 |
| AI/챗 UI | 채팅 입력창, 메시지 형태 UI 구성 |
| 배포 | Streamlit Community Cloud 등으로 공유 가능 |
이번 포스팅 시리즈에서는 스트림릿을 다뤄보도록 하겠습니다.
"""
# markdown
st.markdown(content)
# button
if st.button("Send baloons"):
st.balloons()
st.markdown(content): 마크다운 문법 표현
이 앱을 실행시킨 결과는 아래와 같다.

3. 차트
streamlit은 다양한 차트를 지원한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 03_charts.py
import streamlit as st
import pandas as pd
import numpy as np
st.title("03. 차트")
st.write("Streamlit 은 다양한 데이터 시각화를 지원합니다.")
# 1. 사용자 선택 인터랙션 박스
all_users = ["Alice", "Bob", "Charly"]
with st.container(border=True):
users = st.multiselect("Users", all_users, default=all_users)
rolling_average = st.toggle("Rolling average")
# 2. 데이터 만들기
np.random.seed(42)
data = pd.DataFrame(np.random.randn(20, len(users)), columns=users)
if rolling_average:
data = data.rolling(7).mean().dropna()
# 3. 페이지 내부 탭에 차트 표시
tab1, tab2, tab3 = st.tabs(["Chart", "Scatter", "Dataframe"])
tab1.line_chart(data, height=250)
tab2.scatter_chart(data, height=250)
tab3.dataframe(data, height=250, use_container_width=True)
앱 실행 결과

- Streamlit에서 사용할 수 있는 차트들
| Streamlit 메서드 | 설명 |
|---|---|
st.area_chart() |
면적 차트. 간단한 데이터프레임을 빠르게 시각화할 때 사용. |
st.bar_chart() |
막대 차트를 표시. 범주형 데이터 비교, 집계값 비교에 자주 사용. |
st.line_chart() |
선 차트를 표시. 시간 흐름, 추세, 연속값 변화 시각화에 적합 |
st.scatter_chart() |
산점도를 표시. 두 변수 간 관계, 분포, 군집 확인에 사용 |
st.map() |
위도·경도 데이터를 지도 위 점으로 표시. 위치 기반 데이터 시각화에 사용. |
st.altair_chart() |
Altair 차트를 Streamlit에 표시. (Altair : Vega/Vega-Lite 기반의 선언형 통계 시각화 라이브러리.) |
st.vega_lite_chart() |
Vega-Lite 명세를 사용해 차트를 표시. (Vega-Lite: 인터랙티브 그래픽을 정의하는 고수준 문법.) |
st.plotly_chart() |
Plotly 인터랙티브 차트를 표시. 확대, 이동 등 상호작용 필요 차트에 적합. (사용하려면 plotly>=4.0.0 설치가 필요.) |
st.pyplot() |
Matplotlib의 pyplot figure를 표시.(기존 Matplotlib 코드를 Streamlit 앱에 넣을 때 사용) |
st.pydeck_chart() |
PyDeck 차트를 표시. 3D 지도, 지도 레이어, 포인트 클라우드 등 공간 데이터 시각화에 적합. |
st.graphviz_chart() |
Graphviz 명세 기반 그래프를 표시. 노드와 엣지로 구성된 관계도, DAG, 플로우 구조 표현에 사용. |
4. 데이터프레임
Streamlit에서는 데이터프레임을 표 형태로 표현할 수 있다. 뿐만 아니라 이미지 컬럼, 프로그레스 바 컬럼 등 다양한 컬럼 형식을 지원하고, 웹앱에서 실시간 편집 기능도 제공한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 04.dataframe.py
import streamlit as st
import pandas as pd
import numpy as np
st.title("04. 데이터프레임")
st.write("Streamlit 으로 DataFrame을 보여줄 수 있다.")
st.write("이미지 컬럼, 프로그레스 바 컬럼 등 다양한 컬럼 형식을 지원하고")
st.write("웹앱에서 실시간 편집도 가능하다.")
# 1. 데이터 제작
num_rows = st.slider("Number of Rows", 1, 100, 50)
np.random.seed(42)
data = []
for i in range(num_rows):
data.append(
{
"Preview": f"https://picsum.photos/400/200?lock={i}",
"Size": f"({np.random.randint(800, 1000)}, {np.random.randint(400, 500)})",
"Like": np.random.choice([True, False]),
"Like Ratio": np.random.randint(65, 99),
}
)
data = pd.DataFrame(data)
# 2. 컬럼 설정
config = {
"Preview": st.column_config.ImageColumn(),
"Like Ratio": st.column_config.ProgressColumn()
}
# 3. 데이터프레임 표현 & 편집 가능 여부 설정
if st.toggle("편집 모드"):
edited_data = st.data_editor(data, column_config=config, use_container_width=True)
else:
st.dataframe(data, column_config=config, use_container_width=True)
- 실행 결과

- 지원하는 컬럼 형태
| 컬럼 종류 | 메서드 이름 | 설명 |
|---|---|---|
| 일반 컬럼 | st.column_config.Column() |
기본 컬럼 설정. 라벨, 너비, 도움말, 고정 여부, 정렬 등을 설정할 수 있음. 타입은 데이터에서 자동 추론됨 |
| 텍스트 컬럼 | st.column_config.TextColumn() |
문자열 데이터를 표시하거나 편집할 때 사용. 최대 글자 수, 정규식 검증 등을 설정할 수 있음. |
| 숫자 컬럼 | st.column_config.NumberColumn() |
정수나 실수 데이터를 표시. 최소값, 최대값, 숫자 포맷 등을 설정할 수 있음. |
| 체크박스 컬럼 | st.column_config.CheckboxColumn() |
Boolean 값을 체크박스로 표시. 참/거짓 선택이 필요한 컬럼에 사용. |
| 선택박스 컬럼 | st.column_config.SelectboxColumn() |
미리 정한 옵션 중 하나를 선택하는 컬럼. 카테고리, 상태값, 등급 등에 적합. |
| 다중 선택 컬럼 | st.column_config.MultiselectColumn() |
미리 정한 옵션 중 여러 개를 선택하는 컬럼. 태그, 복수 카테고리 등에 적합. |
| 날짜·시간 컬럼 | st.column_config.DatetimeColumn() |
날짜와 시간을 함께 표시. 예약 시간, 생성 시각, 로그 시간 등에 사용. |
| 날짜 컬럼 | st.column_config.DateColumn() |
날짜만 표시. 생년월일, 마감일, 기준일 등에 사용. |
| 시간 컬럼 | st.column_config.TimeColumn() |
시간만 표시. 시작 시간, 종료 시간, 알림 시간 등에 사용. |
| JSON 컬럼 | st.column_config.JSONColumn() |
JSON 데이터를 구조화해서 표시. 딕셔너리, 설정값, API 응답 등을 보여줄 때 사용. |
| 리스트 컬럼 | st.column_config.ListColumn() |
리스트 형태의 데이터를 표시. 여러 값이 한 셀에 들어가는 경우에 사용. |
| 링크 컬럼 | st.column_config.LinkColumn() |
URL을 클릭 가능한 링크로 표시. 웹사이트, 문서 링크, 상세 페이지 링크에 적합. |
| 이미지 컬럼 | st.column_config.ImageColumn() |
이미지 URL이나 이미지 데이터를 썸네일 형태로 표시. 상품 이미지, 프로필 이미지 등에 사용. |
| 오디오 컬럼 | st.column_config.AudioColumn() |
오디오 데이터를 재생 가능한 형태로 표시. 음성 파일, 효과음, 녹음 데이터 등에 사용. |
| 비디오 컬럼 | st.column_config.VideoColumn() |
비디오 데이터를 재생 가능한 형태로 표시. 영상 클립, 미리보기 영상 등에 사용. |
| 영역 차트 컬럼 | st.column_config.AreaChartColumn() |
한 셀 안에 작은 면적 차트를 표시. 행별 시계열 데이터나 추세 비교에 사용. |
| 선 차트 컬럼 | st.column_config.LineChartColumn() |
한 셀 안에 작은 선 그래프를 표시. 행 단위 변화 추이를 보여줄 때 사용. |
| 막대 차트 컬럼 | st.column_config.BarChartColumn() |
한 셀 안에 작은 막대 그래프를 표시. 행별 구성값이나 비교값을 간단히 보여줄 때 사용. |
| 진행률 컬럼 | st.column_config.ProgressColumn() |
숫자 값을 진행률 막대로 표시. 달성률, 점수, 진행 상태 등을 표현할 때 사용. |
5. LLM Chat
Streamlit은 LLM 채팅 화면을 빠르게 구현하는 도구로도 유명하다. 또한, 이미지나 데이터프레임과 같은 다양한 컨텐츠 유형도 지원한다!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 05_llm_chat.py
import streamlit as st
import random
import time
st.title("05. LLM Chat")
st.markdown("Streamlit은 LLM 채팅 화면을 빠르게 구현하는 도구로도 유명하다. 또한, 이미지나 데이터프레임과 같은 다양한 컨텐츠 유형도 지원한다!")
# 1. 채팅 히스토리 초기화
# st.session_state : 세션 상태
if "messages" not in st.session_state:
st.session_state.messages = [{"role":"assistant", "content":"안녕하세요? 어떻게 도와드릴까요?😀"}] # 세션 상태에 messages와 초기 메시지 할당
# 2. 앱 시작, 재시작시 메시지 출력
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# 3. 사용자의 입력을 받아옴
if prompt := st.chat_input("기본 플레이스홀더"): # 챗 인풋을 받아서
# (1) 세션에 저장
st.session_state.messages.append({"role":"user", "content":prompt})
# (2) 화면에 출력
with st.chat_message("user"):
st.markdown(prompt)
# (3) AI 답변 생성 및 출력
with st.chat_message("assistant"):
message_placeholder = st.empty() # 화면에 출력하는 문자열
full_response = "" # 전체 답변 -> 답변 청크가 모두 끝나고 messages에 저장
assistant_response = random.choice(
[
"안녕하세요? 어떻게 도와드릴까요?",
"아 그러시군요! 잘 알겠어요.",
"무슨 말씀인지 잘 모르겠어요."
]
)
for chunk in assistant_response.split(): # LLM Streaming 답변 재현
full_response += chunk + " "
time.sleep(0.05)
message_placeholder.markdown(full_response + "▌")
message_placeholder.markdown(full_response) # 입력바를 제외한 전체 완성 답변을 화면에 출력
# (4) messages에 AI 생성 답변 저장
st.session_state.messages.append({"role":"assistant", "content":full_response})
- 실행 결과

6. Computer Vision
Streamlit은 전통적 머신러닝 데모 웹앱을 만드는 데에도 유용하다. 아래는 OpenCV의 엣지 검출 결과물을 보여주는 예시다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 06_computer_vision
import streamlit as st
import cv2
import numpy as np
from PIL import Image
import requests
st.title("06. Computer Vision")
st.write("Streamlit은 전통적 머신러닝 데모 웹앱을 만드는 데에도 유용하다.")
# 1. 보여줄 파일 업로드 기능
uploaded_file = st.file_uploader("업로드할 이미지를 선택", type("jpg", "jpeg", "png"))
if uploaded_file:
image = Image.open(uploaded_file)
else:
image = Image.open(requests.get("https://picsum.photos/200/120", stream=True).raw)
# 2. 엣지 검출
edges = cv2.Canny(np.array(image), 100, 200)
# 3. 각 탭에서 엣지와 원본 이미지 표현
tab1, tab2 = st.tabs(["엣지 검출 결과", "원본 이미지"])
tab1.image(edges, use_container_width=True)
tab2.image(image, use_container_width=True)
- 실행 결과

7. Geospatial
지리공간 데이터도 잘 표현할 수 있다. PyDeck, Folium, Kepler.gl 등 다양한 지도 라이브러리를 지원한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import streamlit as st
import pandas as pd
import numpy as np
import pydeck as pdk
st.title("07. 지리공간 시각화")
# 1. 지도 표시 위치 (서울)
lat = 37.5665
lon = 126.9780
# 2. 데이터 만들기
chart_data = pd.DataFrame(
np.random.randn(1000, 2) / [50, 50] + [lat, lon],
columns = ["lat", "lon"]
)
# 3. 지도 시각화
st.pydeck_chart(pdk.Deck(
map_style=None,
initial_view_state=pdk.ViewState(
latitude=lat,
longitude=lon,
zoom=10,
pitch=50
),
layers=[
pdk.Layer(
"HexagonLayer",
data=chart_data,
get_position="[lon, lat]",
radius=150,
elevation_scale=4,
elevation_range=[0, 1000],
pickable=True,
extruded=True
),
pdk.Layer(
"ScatterplotLayer",
data=chart_data,
get_position="[lon, lat]",
get_color="[50, 200, 75, 160]",
get_radius=150,
)
]
))
- 실행 결과

8. 파일 업로드 기능
파일 업로드 기능도 정말 편하게 사용할 수 있게 준비되어있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 08_file_upload.py
import streamlit as st
from PIL import Image
import pandas as pd
import base64
st.title("08. File Upload")
st.write("파일 업로드도 업청 편하다.")
# 0. 이미지를 담고 있는 리스트
if "image_list" not in st.session_state:
image_list = []
st.session_state.image_list = image_list
# 1. 파일 업로드
uploaded_file = st.file_uploader("업로드할 이미지를 선택", type=["jpg", "jpeg", "png"])
# 2. 파일 업로드시 데이터프레임에 추가
if uploaded_file:
file_bytes = uploaded_file.getvalue()
encoded_image = base64.b64encode(file_bytes).decode()
mime_type = uploaded_file.type
st.session_state.image_list.append({"image_name":uploaded_file.name, "image":f"data:{mime_type};base64,{encoded_image}"})
# 3. 데이터프레임 표출
config = {"image":st.column_config.ImageColumn()}
st.dataframe(pd.DataFrame(st.session_state.image_list), column_config=config, use_container_width=True)
- 실행 결과

9. 그 외
그 외 다양한 기능들에 대해서는 streamlit DOC 참고
Reference
Streamlit • A faster way to build and share data apps
[시리즈] Streamlit 웹앱을 클라우드로 배포하기
Streamlit + Supabase로 내가 만든 웹앱을 배포해보자
- ▶ [Python] Streamlit - 파이썬으로 웹앱 만들기
- [Python] Streamlit 에서 JavaScript 사용하기
Comments