Dreep vs UploadThing
UploadThing is an upload service: type-safe file routes, drop-in React components and file storage, with resizing left to your framework or another tool. Dreep covers uploads too, through presigned URLs and SDKs, and adds image and video transformations, OCR, signed delivery URLs and optional storage in your own bucket. Choose UploadThing for a ready-made Next.js upload UI; choose Dreep when files need processing after upload.
Feature comparison
UploadThing figures are from its pricing page and documentation at the time of writing (October 2026). Dreep figures are from the live plans on the pricing page.
| Capability | UploadThing | Dreep |
|---|---|---|
| Main job | Getting files from the browser into storage, with typed routes and components. | Uploads, storage, image and video transformations, OCR, background removal and delivery. |
| Pricing | Free with 2 GB. $10/mo for 100 GB. $25/mo usage-based with 250 GB, then $0.08 per GB. | Free with 1 GB. Starter $2.99/mo with 10 GB. Pro $5.99/mo with 50 GB. Storage add-ons from $1.99/mo. |
| Upload rules | Per-route file types, maxFileSize and maxFileCount, plus server middleware for auth. | Type allow-list, 500 MB per file, Content-Type and Content-Length must match the presign, single-use URLs valid 10 minutes. Your backend decides who may presign. |
| Frontend components | UploadButton and UploadDropzone, generated with your router's types. | None. Any frontend PUTs to the presigned URL with fetch. |
| Image resizing | Not built in. The docs point to your framework's optimiser, for example next/image with remotePatterns. | width, height, fit, format, quality, gravity, dpr and more on the delivery URL. Saved presets. |
| Video | Stored and served as uploaded. | Transcode to MP4, WebM or MOV, trim, HLS, GIF, thumbnails and audio extraction. |
| Private files | private ACL per route. Signed URLs via generateSignedURL, up to 7 days. | Public, Private or Signed folders. HMAC-SHA256 signed URLs generated locally, with any transform. |
| Storage location | UploadThing storage, with region choice on paid plans. | Dreep storage, or your own S3, R2, Wasabi, Spaces or MinIO bucket on Starter and Pro (BYOB). |
| SDKs | TypeScript packages for Next.js, React and other frameworks, plus server adapters. | JavaScript/TypeScript and Go SDKs with zero dependencies, plus REST. |
Cost: storing files against serving them in several sizes
UploadThing prices by storage: a free 2 GB tier, $10 a month for 100 GB, and a $25 usage-based plan with 250 GB included and $0.08 per GB after that. It does not sell image transformations, so resizing is a separate line in your budget. Dreep plans include storage and transformation allowances together.
Assumptions
- A SaaS app with 60 GB of user-uploaded images.
- Each image shown at two sizes in the app: an avatar or thumbnail and a larger preview.
- 30,000 resized image responses a month.
- Dreep counts every request for a transformed variant against the monthly image transformation allowance; originals are never counted.
- Published USD prices at the time of writing (October 2026), before tax. Your hosting provider's image optimisation charges are not included.
UploadThing
- 100GB App plan
- $10.00
- 60 GB of files, inside the 100 GB
- $0.00
- Resizing via your framework or another service
- Varies
Dreep Pro
- Pro plan, 50 GB and 50,000 image transformations
- $5.99
- +10 GB storage add-on
- $1.99
- 30,000 transformations, inside the 50,000
- $0.00
If your app only stores files and serves them as uploaded, UploadThing's 100 GB plan is the simpler purchase and the resizing line disappears. The comparison only tilts towards Dreep once you need several sizes of each image, video processing or OCR, because those come out of the same plan. Past 100 GB, UploadThing's usage-based plan starts at $25 with 250 GB. On Dreep, BYOB on Starter or Pro keeps files in your own bucket, and those bytes do not count against Dreep's storage quota; you pay your bucket provider instead.
The Dreep browser upload flow
UploadThing's middleware runs on your server before an upload and decides who may send files. Dreep's equivalent is the presign step: your backend checks the user, asks Dreep for a single-use upload URL, and the browser sends the bytes straight to it. Your API key never reaches the client.
Browser
Asks your backend to upload a file
Your backend
Checks the user, calls presignUpload
PUT bytes
Single-use URL, valid 10 minutes
Confirm
confirmUpload marks the asset ready
Deliver
dreep.url(asset, { width, format })
File routes against presigned uploads, in code
On the left, UploadThing's App Router example: a typed file route with limits and an auth check. Dreep has no client components, so the same job is a few lines on your server plus a fetch call in the browser, after which the asset can be resized from its URL.
// app/api/uploadthing/core.ts
import { createUploadthing, type FileRouter } from "uploadthing/next";
import { UploadThingError } from "uploadthing/server";
const f = createUploadthing();
export const ourFileRouter = {
imageUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 1 } })
.middleware(async ({ req }) => {
const user = await auth(req); // your auth helper
if (!user) throw new UploadThingError("Unauthorized");
return { userId: user.id };
})
.onUploadComplete(async ({ metadata, file }) => {
console.log("file url", file.ufsUrl);
return { uploadedBy: metadata.userId };
}),
} satisfies FileRouter;
// app/api/uploadthing/route.ts
import { createRouteHandler } from "uploadthing/next";
export const { GET, POST } = createRouteHandler({ router: ourFileRouter });// Server: your auth check, then a short-lived upload URL
import { Dreep } from "dreep";
const dreep = new Dreep({ apiKey: process.env.DREEP_API_KEY });
export const createUpload = async ({ user, filename, contentType, sizeBytes }) => {
if (!user) throw new Error("Unauthorized");
return dreep.presignUpload({
filename,
contentType,
sizeBytes,
folder: `users/${user.id}`,
});
};
// Browser: upload is what createUpload returned
await fetch(upload.uploadUrl, { method: "PUT", body: file });
// Server: finalise, then serve any size from the asset URL
const asset = await dreep.confirmUpload({ id: upload.id });
dreep.url(asset, { width: 96, height: 96, fit: "cover", format: "webp" });client, err := dreep.New(os.Getenv("DREEP_API_KEY"))
if err != nil {
log.Fatal(err)
}
// Presign, PUT and confirm in one call
asset, err := client.UploadPresigned(ctx, dreep.DirectUploadOptions{
PresignOptions: dreep.PresignOptions{
ContentType: "image/jpeg",
SizeBytes: size,
Filename: "avatar.jpg",
},
File: f,
})
if err != nil {
log.Fatal(err)
}
avatar := client.URL(asset.ID, &dreep.Transform{Width: 96, Format: dreep.FormatWebP})# 1. Your backend asks for an upload URL
curl -X POST https://api.dreep.cloud/api/v1/upload/presign \
-H "Authorization: Bearer $DREEP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filename":"avatar.jpg","contentType":"image/jpeg","sizeBytes":245000}'
# 2. The client PUTs the bytes to the returned uploadUrl
curl -X PUT "$UPLOAD_URL" -H "Content-Type: image/jpeg" --data-binary @avatar.jpg
# 3. Your backend confirms
curl -X POST https://api.dreep.cloud/api/v1/upload/$UPLOAD_ID/confirm \
-H "Authorization: Bearer $DREEP_API_KEY"
# Serve a 96px WebP avatar
https://cdn.dreep.cloud/api/v1/fetch/<ASSET_ID>.jpg?width=96&height=96&fit=cover&format=webpWhat you get after the upload finishes
Every size from one upload
Store one original and request avatar, card and full-width sizes from its URL. Each size is generated on first request and cached, so there is no resize step in your upload handler.
Video that plays on phones
A user's MOV from an iPhone can be served as MP4 or packaged as HLS from the same asset. Heavy jobs return 202 while processing; you re-request the URL until it returns 200.
Files in an account you own
On Starter and Pro, BYOB writes originals and generated variants to your own S3-compatible bucket. Useful when contracts or data policies say where customer files must live.
Documents as data
Uploaded receipts, invoices and scanned PDFs can be read as text through format=txt, billed per OCR page, without wiring up a separate OCR service.
Where UploadThing is the better choice
UploadThing is built around developer experience for React apps, and it does that job well. Pick it in these cases.
Fastest path to an upload UI in React
UploadButton and UploadDropzone give you progress, drag and drop and error states without writing a component. Dreep gives you a URL to PUT to and leaves the UI to you.
Type safety from server to client
Components are generated from your file router's type, so endpoint names and returned metadata are checked at compile time across the network boundary.
Declarative per-route rules
File types, size and count limits sit next to the auth middleware for each route, which keeps upload policy easy to read and review.
Files that need no processing
If you serve PDFs, zips and images as uploaded, UploadThing's storage-only pricing is straightforward and you are not paying for transformation allowances you will not use.
Who this is for
- Apps that show user uploads at several sizes, or need video transcoding and HLS.
- Teams outside React, or with a Go backend, who want a plain presign, PUT and confirm flow.
- Products that must keep files in their own S3, R2, Wasabi, Spaces or MinIO bucket.
- Apps that extract text from uploaded receipts, forms or PDFs.
When Dreep is not the right fit
- Next.js teams who mainly want drop-in upload components with end-to-end types.
- Apps that store and serve files exactly as uploaded, with no resizing or video work.
- Teams that expect the upload service to scan files for malware; Dreep does not.
- Anyone needing upload completion webhooks; Dreep has no customer-facing webhooks.
Migrating from UploadThing
There is no automatic UploadThing importer in Dreep, so a move is a short script. Your upload UI changes; your storage of file keys in your own database stays the same shape.
- 1
Replace the file route with a presign endpoint
Move the logic from your middleware (who may upload, which folder) into a server route that calls presignUpload, and a second route that calls confirmUpload.
- 2
Swap the upload component
Replace UploadButton or UploadDropzone with your own input that PUTs to uploadUrl. Keep the file type and size rules on your server, before presigning.
- 3
Copy existing files
List files with UTApi's listFiles, download each from its file URL, and upload it to Dreep with the SDK. Store the new asset ID next to the old file key.
- 4
Replace resize logic with URL parameters
Remove client-side resizing or framework image optimiser rules for these files and request sizes with dreep.url, or define presets for the sizes you reuse.
- 5
Cut over and clean up
Point new uploads at Dreep first, backfill old files, then switch reads. Delete files from UploadThing with deleteFiles once nothing references them.
Frequently asked questions
Does Dreep have React upload components like UploadThing?
No. Dreep gives your backend a presigned, single-use upload URL and the browser sends a plain PUT with fetch. You build the input, progress and error UI yourself, or reuse an upload component you already have.
Can I upload to Dreep directly from the browser?
Yes, through the presigned flow. The API key is a full-project credential and must stay on your server; the JavaScript SDK refuses to run in a browser. Your backend authorises the user, calls presignUpload, and the browser PUTs to the returned URL.
How do I resize images stored in UploadThing?
UploadThing does not offer its own transformations; its docs show restricting next/image's remotePatterns to your app's file host so the framework optimiser can handle them. With Dreep, resizing is part of the delivery URL.
What file size can each service accept?
UploadThing sets limits per route, with defaults such as 4 MB for images and 16 MB for video that you can raise. Dreep accepts up to 500 MB per file, and recommends the presigned flow for large files.
Can I keep UploadThing for some files and use Dreep for others?
Yes. A common split is UploadThing for document attachments served as-is, and Dreep for images and video that need several sizes or formats. The two do not share storage, so pick one home per file type.
Related
All comparisons
How Dreep compares with other media and storage services.
Dreep vs Cloudflare Images
Per-image pricing and variants against flat plans and URL parameters.
Dreep vs Supabase Storage
Storage with Postgres policies against a dedicated media API.
Cloudinary alternative
Moving from Cloudinary, with the built-in importer.
Image CDN API
Every image transform parameter, with examples.
Pricing
Plans, allowances and add-on packs in full.
Documentation
Presigned uploads, transformations and SDK references.
Wire up a presigned upload in one sitting
Install the SDK, add a presign and a confirm route, and serve your first resized image from the Free plan's 1 GB and 100 monthly transformations.
Sources
UploadThing facts on this page were checked against these official pages in October 2026.