[시리즈] Streamlit 웹앱을 클라우드로 배포하기

Streamlit + Supabase로 내가 만든 웹앱을 배포해보자

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 참고

Streamlit Docs

Reference

Streamlit • A faster way to build and share data apps

Playground • Streamlit

[시리즈] Streamlit 웹앱을 클라우드로 배포하기

Streamlit + Supabase로 내가 만든 웹앱을 배포해보자

Comments