Skip to content
PutPut is shutting down on October 21, 2026. New signups, uploads, and paid plans are closed. Please download your files before then.

PutPut vs the Alternatives

Developers waste hours evaluating file upload services. We did the work for you. Each comparison breaks down pricing, setup time, lock-in, and what actually matters when you just need to upload a file and get a URL.

PutPut vs UploadThing

UploadThing is a great file upload library for Next.js, but it requires a framework-specific file router and an account. PutPut is framework-agnostic and works with plain HTTP requests.

FeaturePutPutUploadThing
Signup required No Yes (account + API key)
Setup time< 1 minute5-10 minutes
Framework lock-in None (plain HTTP) Next.js / Solid / Svelte
Server component needed No Yes (file router)
Egress fees $0Included (limits apply)
Free tier storage10 GB2 GB
AI-friendly docs docs.putput.io No
Self-hostable Yes (Cloudflare) No
Direct-to-storage uploads Yes (R2 presigned) Yes
Guest tokens (no auth) Yes No

Code comparison

PutPut
// Works in any framework or plain JS
const tok = await fetch('/api/v1/auth/guest',
  { method: 'POST' }).then(r => r.json());

const pre = await fetch('/api/v1/upload/presign',
  { method: 'POST',
    headers: { Authorization: `Bearer ${tok.token}` },
    body: JSON.stringify({ filename: 'doc.pdf',
      content_type: 'application/pdf' }) }
).then(r => r.json());

await fetch(pre.upload_url,
  { method: 'PUT', body: file });

const result = await fetch('/api/v1/upload/confirm',
  { method: 'POST',
    headers: { Authorization: `Bearer ${tok.token}` },
    body: JSON.stringify({ upload_id: pre.upload_id }) }
).then(r => r.json());
UploadThing
// 1. Define file router (server)
import { createUploadthing }
  from 'uploadthing/next';

const f = createUploadthing();
export const uploadRouter = {
  docUploader: f({
    pdf: { maxFileSize: '4MB' }
  })
    .middleware(async () => {
      // Auth check required
      return { userId: 'abc' };
    })
    .onUploadComplete(async ({ file }) => {
      console.log('uploaded', file.url);
    }),
};

// 2. Create API route (server)
import { createRouteHandler }
  from 'uploadthing/next';
export const { GET, POST } =
  createRouteHandler({ router });

// 3. Use component (client)
import { UploadButton }
  from '@uploadthing/react';
<UploadButton endpoint="docUploader" />

They ship a React library. We ship an API.

UploadThing works well if your entire stack is React or Next.js. But what happens when you add a mobile app, a CLI tool, or an AI agent? You need a different integration for each one — or you rewrite.

PutPut is plain HTTP. Any language, any framework, any runtime. Here's the same upload in three languages:

PutPut — JavaScript
const res = await fetch(presignUrl,
  { method: 'PUT', body: file });
const { url } = await fetch(confirmUrl,
  { method: 'POST',
    headers: { Authorization: `Bearer ${token}` },
    body: JSON.stringify({ upload_id }) }
).then(r => r.json());
PutPut — Python
import requests

requests.put(presign_url, data=file_bytes)
result = requests.post(confirm_url,
  headers={"Authorization": f"Bearer {token}"},
  json={"upload_id": upload_id})
url = result.json()["url"]
PutPut — cURL
# Upload the file
curl -X PUT "$PRESIGN_URL" \
  --data-binary @photo.jpg

# Confirm and get the public URL
curl -X POST "$API/upload/confirm" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"upload_id": "'$UPLOAD_ID'"}'
UploadThing
// Requires Next.js or Solid or Svelte
import { createUploadthing }
  from 'uploadthing/next';
import { UploadButton }
  from '@uploadthing/react';

// Needs: file router, API route handler,
// React component, and server middleware
// — all framework-specific

UploadThing requires a framework-specific file router, server middleware, and a React (or Solid/Svelte) component. Switching frameworks means rewriting your upload integration.

Frequently asked questions

What's the difference between PutPut and UploadThing?

PutPut works with any framework via plain HTTP calls. UploadThing requires a specific framework integration (Next.js, Solid, Svelte). PutPut also offers 10 GB free storage vs UploadThing's 2 GB.

Is PutPut free?

Yes. PutPut has a free tier with 10 GB storage, unlimited files, and $0 egress. No credit card required.

Does PutPut require a specific framework?

No. PutPut is framework-agnostic. It works with Next.js, SvelteKit, Nuxt, Rails, or any language that can make HTTP requests.

Does PutPut have egress fees?

No. PutPut has $0 egress fees on every plan, powered by Cloudflare R2.

Get started for free

No signup required. No credit card.

v0.4.78