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 Cloudinary

Cloudinary is a powerful media platform — image transforms, video processing, a full DAM. But if you just need to upload files and get a URL back, it's overkill. PutPut is purpose-built for the upload-and-serve use case.

FeaturePutPutCloudinary
Signup required No Yes (account + API key)
Setup time< 1 minute10-20 minutes
Free tier storage10 GB25 credits/mo (~25 GB, shared with transforms)
Egress fees $0 Credits consumed per delivery
Pricing model Free (no paid tier yet)From $89/mo
Media transformations Not needed — upload & serve Full pipeline (resize, crop, effects)
SDK required No (plain HTTP) Yes (cloudinary SDK)
AI-friendly docs docs.putput.io No
Framework lock-in None (plain fetch) None (SDK is framework-agnostic)
Direct-to-storage uploads Yes (R2 presigned) Yes (unsigned uploads)

Code comparison

PutPut
// Get a token (no signup)
const tok = await fetch('/api/v1/auth/guest',
  { method: 'POST' }).then(r => r.json());

// Upload a file
const pre = await fetch('/api/v1/upload/presign',
  { method: 'POST',
    headers: { Authorization: `Bearer ${tok.token}` },
    body: JSON.stringify({ filename: 'photo.jpg',
      content_type: 'image/jpeg' }) }
).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());
Cloudinary
// Install cloudinary SDK, configure
import { v2 as cloudinary } from 'cloudinary';

cloudinary.config({
  cloud_name: process.env.CLOUD_NAME,
  api_key: process.env.API_KEY,
  api_secret: process.env.API_SECRET,
});

// Server-side: generate signature
const timestamp = Math.round(Date.now() / 1000);
const signature = cloudinary.utils
  .api_sign_request(
    { timestamp, folder: 'uploads' },
    process.env.API_SECRET!
  );

// Client-side: upload via form data
const form = new FormData();
form.append('file', file);
form.append('api_key', API_KEY);
form.append('timestamp', String(timestamp));
form.append('signature', signature);
form.append('folder', 'uploads');

const res = await fetch(
  `https://api.cloudinary.com/v1_1/${CLOUD}/image/upload`,
  { method: 'POST', body: form }
);

Frequently asked questions

Is Cloudinary overkill for simple file uploads?

If you just need to upload files and serve them via a URL, yes. Cloudinary is a full media platform with image/video transformations, a DAM, and delivery optimization. PutPut is purpose-built for the upload-and-serve use case — no extra complexity.

Does PutPut support image transformations?

No, and that's intentional. PutPut stores and serves your files as-is. If you need on-the-fly resizing or format conversion, Cloudinary is the better choice. But most apps handle transforms client-side or at build time.

How does Cloudinary's credit system work?

Cloudinary uses a credit-based system where storage, transformations, and bandwidth all consume credits from a shared pool. The free tier gives 25 credits/month. One credit roughly equals 1 GB of storage or 1 GB of delivery, but transformations cost additional credits.

Can I migrate from Cloudinary to PutPut?

Yes. Since PutPut uses standard HTTP uploads, you can re-upload your files using any script or tool. No SDK changes needed — just point your upload logic at the PutPut API.

Get started for free

No signup required. No credit card.

v0.4.78