CDN & Storage
Upload files to global CDN storage with automatic optimization and fast delivery.
Upload Flow
File uploads use a two-step process for security and efficiency:
- Request a presigned upload URL from the API
- Upload the file directly to S3 using the presigned URL
- Confirm the upload is complete
Basic Upload
upload.ts
import { Stack0 } from '@stack0/sdk'const stack0 = new Stack0({apiKey: process.env.STACK0_API_KEY!})// Step 1: Get a presigned upload URLconst { uploadUrl, assetId, cdnUrl } = await stack0.cdn.getUploadUrl({filename: 'profile.jpg',mimeType: 'image/jpeg',size: file.size, // File size in bytes})// Step 2: Upload directly to S3await fetch(uploadUrl, {method: 'PUT',body: file,headers: {'Content-Type': 'image/jpeg',},})// Step 3: Confirm the uploadawait stack0.cdn.confirmUpload({ assetId })// The file is now available at cdnUrlconsole.log('File available at:', cdnUrl)
Upload Options
| Option | Type | Description |
|---|---|---|
| filename | string | Original filename (required) |
| mimeType | string | MIME type (required) |
| size | number | File size in bytes (required, max 100MB) |
| folder | string | Organize into folders |
| metadata | object | Custom metadata |
Organize with Folders
folders.ts
// Upload to a specific folderconst { uploadUrl, assetId, cdnUrl } = await stack0.cdn.getUploadUrl({filename: 'avatar.jpg',mimeType: 'image/jpeg',size: file.size,folder: 'users/avatars',})// Upload product imagesconst productUpload = await stack0.cdn.getUploadUrl({filename: 'hero.png',mimeType: 'image/png',size: file.size,folder: 'products/SKU-12345',})
Get Asset Details
get-asset.ts
const asset = await stack0.cdn.get({ id: 'asset_xxx' })console.log('Filename:', asset.filename)console.log('Size:', asset.size, 'bytes')console.log('Type:', asset.type) // 'image' | 'video' | 'audio' | 'document' | 'other'console.log('CDN URL:', asset.cdnUrl)console.log('Dimensions:', asset.width, 'x', asset.height) // For imagesconsole.log('Created:', asset.createdAt)
List Assets
list-assets.ts
// List all assetsconst { assets, total, hasMore } = await stack0.cdn.list({limit: 50,offset: 0,})// Filter by folderconst userAvatars = await stack0.cdn.list({folder: 'users/avatars',})// Filter by typeconst images = await stack0.cdn.list({type: 'image',})// Search by filenameconst results = await stack0.cdn.list({search: 'hero',})// Sort by date or sizeconst recent = await stack0.cdn.list({sortBy: 'createdAt',sortOrder: 'desc',})
Update Asset
update-asset.ts
// Update asset metadataconst updated = await stack0.cdn.update({id: 'asset_xxx',filename: 'new-name.jpg',folder: 'archived',tags: ['product', 'hero'],alt: 'Product hero image',})
Move Assets
move-assets.ts
// Move multiple assets to a folderconst result = await stack0.cdn.move({assetIds: ['asset_xxx', 'asset_yyy', 'asset_zzz'],folder: 'archived/2024',})console.log(`Moved ${result.movedCount} assets`)// Move to root folderawait stack0.cdn.move({assetIds: ['asset_xxx'],folder: null, // null = root})
Delete Assets
delete-assets.ts
// Delete a single assetawait stack0.cdn.delete({ id: 'asset_xxx' })// Delete multiple assetsconst result = await stack0.cdn.deleteMany({ids: ['asset_xxx', 'asset_yyy', 'asset_zzz'],})console.log(`Deleted ${result.deletedCount} assets`)
Browser Upload Example
Complete example for handling file uploads in a React component:
components/file-upload.tsx
// Client component'use client'import { useState } from 'react'export function FileUpload() {const [uploading, setUploading] = useState(false)const [url, setUrl] = useState<string | null>(null)async function handleUpload(e: React.ChangeEvent<HTMLInputElement>) {const file = e.target.files?.[0]if (!file) returnsetUploading(true)try {// Get upload URL from your APIconst res = await fetch('/api/upload', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({filename: file.name,mimeType: file.type,size: file.size,}),})const { uploadUrl, assetId, cdnUrl } = await res.json()// Upload to S3await fetch(uploadUrl, {method: 'PUT',body: file,headers: { 'Content-Type': file.type },})// Confirm uploadawait fetch('/api/upload/confirm', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ assetId }),})setUrl(cdnUrl)} finally {setUploading(false)}}return (<div><input type="file" onChange={handleUpload} disabled={uploading} />{uploading && <p>Uploading...</p>}{url && <img src={url} alt="Uploaded" />}</div>)}