Store uploads on your own server's disk, for self-hosted apps, VPSs and local development.
import { createFileSystemStorage } from "@uploadcn/server/fs"createFileSystemStorage implements the same storage interface as S3, so the browser
side doesn't change: s3Adapter uploads through signed URLs, with multipart and resume.
Bytes are streamed to disk, never buffered whole in memory.
Node.js servers only
Serverless platforms (Vercel functions, Lambda, Workers) have no persistent disk. Use it on a VPS, a container with a volume, or locally.
Create the storage
import { createFileSystemStorage } from "@uploadcn/server/fs"
export const files = createFileSystemStorage({
directory: "./uploads",
baseUrl: "/api/files",
secret: process.env.UPLOAD_SIGNING_SECRET!, // a long random string
})Mount the routes
The upload route signs requests. The file handler receives the bytes and serves signed downloads.
import { createUploadRoute } from "@uploadcn/server"
import { files } from "@/lib/storage"
export const { POST } = createUploadRoute({ storage: files.storage })import { files } from "@/lib/storage"
export const PUT = files.handler
export const GET = files.handlerPoint components at it
const adapter = s3Adapter({ endpoint: "/api/upload" })Public files
By default, getUrl returns a short-lived signed download URL. To serve files publicly,
for example from public/uploads, set publicUrl:
createFileSystemStorage({
directory: "./public/uploads",
publicUrl: "/uploads",
baseUrl: "/api/files",
secret: process.env.UPLOAD_SIGNING_SECRET!,
})Security
- Upload and download URLs are HMAC-signed, expire, and are bound to one method, so a download URL can't be used to upload.
- Object keys can't escape
directory:.., absolute paths and the internal parts folder are rejected. - A signed single upload must match its declared size exactly; anything larger is rejected while streaming.
- Files are written to a temporary path and renamed when complete, so readers never see half-written files.
- Downloads are served with
x-content-type-options: nosniff.
Options
Prop
Type