본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 15. 14:53

파일 업로드 아키텍처: TanStack Start에서의 R2, Multipart 및 Streaming

요약

TanStack Start와 Cloudflare R2를 활용하여 에지 네이티브 성능을 갖춘 파일 업로드 아키텍처를 구축하는 방법을 설명합니다. 멀티파트 폼 업로드부터 Presigned URL을 통한 직접 업로드, 대용량 파일을 위한 청크 업로드 방식까지 다양한 구현 패턴을 다룹니다.

핵심 포인트

  • TanStack Start와 Cloudflare R2를 결합한 에지 기반 업로드 아키텍처 구축
  • 소규모 파일에 적합한 서버 함수 기반 멀티파트 폼 업로드 구현
  • 대용량 파일 처리를 위한 Presigned URL 및 브라우저 직접 업로드 방식
  • 안정적인 대용량 전송을 위한 청크(Chunk) 기반 업로드 및 진행률 관리

파일 업로드는 프로필 이미지, 문서 첨부 파일, 미디어 라이브러리, 데이터 가져오기 등 대부분의 SaaS 애플리케이션에서 매우 중요한 기능입니다. Cloudflare Workers 기반의 TanStack Start는 R2 오브젝트 스토리지(object storage)와 결합하여 에지 네이티브(edge-native) 성능을 갖춘 완전한 업로드 아키텍처를 제공합니다. 이 가이드에서는 멀티파트 폼 업로드(multipart form uploads), 브라우저에서 R2로의 직접 업로드, 대용량 파일을 위한 스트리밍 업로드(streaming uploads), 이미지 처리 파이프라인, 액세스 제어(access control), 그리고 tanstackship.com에서 사용되는 프로덕션 수준의 업로드 흐름을 다룹니다.

아키텍처 개요 (Architecture Overview)

구성 요소목적성능
Browser파일 선택, 청킹(chunking), 진행률클라이언트 측 (Client-side)
...

멀티파트 폼 업로드 (Multipart Form Upload)

가장 간단한 접근 방식은 TanStack Start의 서버 함수(server functions)를 사용하여 폼 제출의 일부로 파일을 업로드하는 것입니다:

// server/uploads.ts
import { createServerFn } from "@tanstack/react-start"

...
// Client component
import { useMutation } from "@tanstack/react-query"
import { uploadProfileImage } from "../server/uploads"
...

R2 직접 업로드 (Presigned URLs)

더 큰 파일의 경우, 미리 서명된 URL(presigned URLs)을 사용하여 Worker를 완전히 우회하고 브라우저에서 R2로 직접 업로드하십시오:

// server/uploads.ts
export const getUploadUrl = createServerFn({ method: "GET" }).handler(
  async ({ data, context }: { data: { filename: string; contentType: string } }) => {
...
// Client — R2로 직접 업로드
async function uploadDirect(file: File) {
  const { uploadUrl } = await getUploadUrl({
...

각 방식의 사용 시점

방식파일 크기사용 사례장점단점
Worker를 통한 Form data< 5 MB프로필 사진, 문서단순함, Worker 내 검증 가능Worker 실행 시간
...

대용량 파일을 위한 청크 업로드 (Chunked Upload for Large Files)

// server/uploads.ts
export const initiateMultipartUpload = createServerFn({ method: "POST" }).handler(
  async ({ data }: { data: { filename: string; parts: number } }) => {
...

// 클라이언트 — 진행률을 포함한 청크 업로드 (chunked upload)
async function uploadLargeFile(file: File, onProgress: (pct: number) => void) {
const CHUNK_SIZE = 5 * 1024 * 1024 // 5MB
...


## 이미지 처리 파이프라인 (Image Processing Pipeline)

R2를 Cloudflare Image Resizing 또는 Workers 기반의 파이프라인과 결합하세요:

// server/images.ts
export const processAndUploadImage = createServerFn({ method: "POST" }).handler(
async ({ data, context }) => {
...


## 액세스 제어 (Access Control)

### 비공개 콘텐츠를 위한 서명된 URL (Signed URLs)

export const getSignedDownloadUrl = createServerFn({ method: "GET" }).handler(
async ({ data, context }: { data: { key: string } }) => {
// 권한 확인 (Check authorization)
...


## 파일 검증 미들웨어 (File Validation Middleware)

// server/uploads.ts
const fileValidators = {
image: {
...


## 비용 분석: R2 vs S3 vs 로컬 스토리지 (Cost Analysis: R2 vs S3 vs Local Storage)

| 스토리지 제공업체 (Storage Provider) | 스토리지 (1TB) | 이그레스 (Egress, 1TB) | A 작업 (10M) | B 작업 (10M) |
| --- | --- | --- | --- | --- |
| **Cloudflare R2** | $15.00 | $0.00 | $0.36 | $0.36 |
| ... |

사용자가 업로드된 파일에 빈번하게 접근하는 SaaS 애플리케이션의 경우, R2의 제로 이그레스(zero egress) 비용은 상당한 이점입니다.

## 프로덕션 보안 체크리스트 (Production Security Checklist)

- [ ] 클라이언트와 서버 양측에서의 파일 유형 검증 (File type validation)
- [ ] 파일 크기 제한 강제 — 처리 전 용량이 초과된 업로드 거부
- [ ] 경로 탐색(path traversal) 방지를 위한 UUID 기반의 고유 파일명 사용
- [ ] R2 객체에 Content-Type 헤더 명시적 설정
- [ ] 짧은 만료 시간을 가진 서명된 URL (Presigned URLs) (PUT은 최대 1시간, GET은 1일)
- [ ] 다운로드 URL 생성 전 권한 확인 (Authorization check)
- [ ] 사용자당 업로드 속도 제한 (Rate limiting, 남용 방지)
- [ ] 문서 업로드 시 바이러스 스캔 (Workers 상의 WebAssembly 기반 ClamAV)
- [ ] 오리진(origins)을 제한하는 R2 버킷의 CORS 설정
- [ ] 모든 업로드 및 다운로드 이벤트에 대한 감사 로깅 (Audit logging)

## 결론 (Conclusion)

파일 업로드 아키텍처 (File upload architecture)는 모든 SaaS 애플리케이션에서 매우 중요한 고려 사항입니다. TanStack Start + Cloudflare R2는 작은 프로필 이미지부터 수 기가바이트(GB) 단위의 미디어 파일까지 모든 것을 처리할 수 있는 확장 가능하고 비용 효율적인 기반을 제공합니다.

주요 아키텍처 결정 사항:

1. **작은 파일 (< 5 MB)** — 인라인 검증 (Inline validation)을 위해 Worker를 통해 업로드
2. **중간 크기 파일 (5-100 MB)** — R2로 직접 업로드를 위한 미리 서명된 URL (Presigned URLs)
3. **대용량 파일 (> 100 MB)** — 진행 상황 추적 (Progress tracking) 기능이 포함된 청크 업로드 (Chunked upload)
4. **비공개 파일** — 권한 확인 (Authorization checks) 기능이 포함된 서명된 URL (Signed URLs)
5. **이미지** — 여러 크기 변형 (Size variants)을 생성하는 처리 파이프라인 (Processing pipeline)

이 아키텍처의 프로덕션 구현에 대해서는 [tanstackship.com](https://tanstackship.com)을 참조하세요.

### 관련 리소스 (Related Resources)

- [Cloudflare R2: 에지 애플리케이션을 위한 객체 스토리지 (Object Storage)](https://tanstackship.com/blog/cloudflare-r2-object-storage-guide)
- [TanStack Start + Drizzle ORM: 데이터베이스 통합 패턴 (Database Integration Patterns)](https://tanstackship.com/blog/tanstack-start-drizzle-orm)
- [현대적 웹 애플리케이션을 위한 이미지 최적화 (Image Optimization)](https://tanstackship.com/blog/image-optimization-web-guide)
- [SaaS 보안 모범 사례 (SaaS Security Best Practices)](https://tanstackship.com/blog/saas-security-best-practices)

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0