개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

Supabase Storage — 파일을 저장하고 제공하는 방법

2025년 4월 14일
SupabaseStorageUploadPublic URLSigned URL

Supabase Storage는 이미지, PDF, 동영상 같은 파일을 저장하고 클라이언트에 제공하는 객체 스토리지 서비스다. S3 호환 API 위에 구축되어 있으며, Row Level Security(RLS)와 동일한 방식으로 접근 권한을 제어할 수 있다. 별도의 스토리지 인프라 없이 Supabase 프로젝트 하나로 DB와 파일을 함께 관리할 수 있다는 점이 가장 큰 장점이다.

구조 개요

Client
  │
  ▼
Supabase Storage API
  │
  ├── Bucket (논리적 컨테이너)
  │     ├── public/  ← Public Bucket
  │     └── private/ ← Private Bucket
  │
  └── Storage Policy (RLS 기반 접근 제어)

Bucket은 파일을 담는 최상위 컨테이너다. Public Bucket의 파일은 URL만 있으면 누구나 접근할 수 있고, Private Bucket의 파일은 Signed URL 또는 인증된 요청을 통해서만 접근 가능하다.

Bucket — S3의 버킷 개념과 동일. 프로젝트 내 여러 개 생성 가능.

Bucket 생성

대시보드 또는 클라이언트 코드로 생성할 수 있다.

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)

// Public Bucket 생성
const { data, error } = await supabase.storage.createBucket('avatars', {
  public: true,
})

파일 Upload / Download / Delete

// Upload
const { error: uploadError } = await supabase.storage
  .from('avatars')
  .upload('user-123/profile.png', file, {
    contentType: 'image/png',
    upsert: true, // 덮어쓰기 허용
  })

// Download (Blob 반환)
const { data: blob, error: downloadError } = await supabase.storage
  .from('avatars')
  .download('user-123/profile.png')

// Delete
const { error: deleteError } = await supabase.storage
  .from('avatars')
  .remove(['user-123/profile.png'])

upsert: true — 동일 경로에 파일이 이미 존재할 때 오류 대신 덮어쓴다.

Public URL vs Signed URL

구분Public URLSigned URL
접근 권한누구나토큰 소지자만
만료 시간없음설정 가능 (초 단위)
용도프로필 이미지, 공개 에셋계약서, 청구서, 비공개 파일
Bucket 조건Public Bucket 필요Private Bucket 가능
// Public URL (즉시 반환, 네트워크 요청 없음)
const { data } = supabase.storage
  .from('avatars')
  .getPublicUrl('user-123/profile.png')

console.log(data.publicUrl)

// Signed URL (60초 유효)
const { data: signed, error } = await supabase.storage
  .from('documents')
  .createSignedUrl('invoices/2026-10.pdf', 60)

console.log(signed?.signedUrl)

Signed URL — 만료 시간이 지나면 해당 URL로 파일에 접근할 수 없다. 민감한 파일에 적합.

Storage Policy 설정

Storage Policy는 SQL로 작성하는 RLS 규칙이다. 인증된 사용자만 자신의 파일을 업로드할 수 있도록 제한하는 예시다.

-- 인증된 사용자만 자신의 폴더에 업로드 허용
CREATE POLICY "Users can upload their own files"
ON storage.objects
FOR INSERT
TO authenticated
WITH CHECK (
  bucket_id = 'avatars' AND
  (storage.foldername(name))[1] = auth.uid()::text
);

-- 모든 사용자가 avatars 버킷 파일 조회 가능
CREATE POLICY "Public read access"
ON storage.objects
FOR SELECT
USING (bucket_id = 'avatars');

storage.foldername — 파일 경로에서 폴더 세그먼트를 배열로 반환하는 Supabase 내장 함수.

이미지 변환 (Image Transformation)

Pro 플랜 이상에서 URL 파라미터로 이미지를 즉시 리사이즈할 수 있다.

const { data } = supabase.storage
  .from('avatars')
  .getPublicUrl('user-123/profile.png', {
    transform: {
      width: 200,
      height: 200,
      resize: 'cover',
    },
  })

별도의 이미지 처리 서버 없이 CDN 엣지에서 변환이 이루어지므로 응답 속도가 빠르다.

← 이전 글Supabase REST API — 테이블에서 자동 생성되는 API
다음 글 →Supabase Realtime — 데이터베이스 변경을 실시간으로 구독