# Comparison (https://v2.s3.dimah.dev/docs/comparison)

File tools solve different layers of the stack. Some provide upload UI, some
manage storage, and some define the server policy around an object throughout
its lifetime.

<Callout title="The short version">
  Choose **dimah-s3** when you want upload, verified confirmation, download,
  deletion, and optional database tracking around an S3-compatible bucket you
  control. Choose **Better Upload** for a smaller upload-focused toolkit,
  **UploadThing** for managed storage, or **Uppy** for a broad client-side
  uploader ecosystem.
</Callout>

## Feature comparison [#feature-comparison]

<div className="hidden md:block">

| Capability                | dimah-s3                         | [Better Upload](https://better-upload.com) | [UploadThing](https://uploadthing.com) | [Uppy](https://uppy.io)     |
| ------------------------- | -------------------------------- | ------------------------------------------ | -------------------------------------- | --------------------------- |
| **Product model**         | Lifecycle toolkit                | Upload toolkit                             | Managed file service                   | Client uploader             |
| **Storage**               | Your S3-compatible bucket        | Your S3-compatible bucket                  | Managed storage and CDN                | Your bucket or service      |
| **Server policy**         | Named lifecycle routes           | Upload routes + S3 helpers                 | Managed file routes                    | Bring your own or Companion |
| **After upload**          | Signed ticket + `HeadObject`     | Client event; app verification             | Managed completion callback            | Your backend                |
| **Download**              | Signed URL or proxy + React API  | Server helpers                             | Public or signed managed URLs          | Your application            |
| **Delete**                | Guarded route + bulk + React API | Server helpers                             | Hosted API                             | Your application            |
| **Multipart and resume**  | Multipart + persistent store     | Multipart + retries                        | Managed pause/resume                   | S3 multipart or Tus         |
| **Ownership and records** | Optional `@dimah-s3/db`          | Your application                           | Service records + app auth             | Your application            |
| **React UI**              | Headless + optional shadcn       | Hooks + shadcn upload UI                   | Components + hooks                     | Headless core + Dashboard   |
| **Cost and operations**   | Cloud + application operations   | Cloud + application operations             | Managed plan + usage                   | Backend + destination costs |

The matrix describes first-party product scope. Every option can be extended
with application code; the sections below explain the practical boundary.

</div>

<div className="md:hidden">

On smaller screens, use the product-model cards and pairwise guidance below;
they cover the same decision boundaries without a wide matrix.

</div>

---

## Choose by responsibility [#choose-by-responsibility]

<Cards>
  <Card
    title="dimah-s3"
    href="/docs/quickstart"
    description="Own the bucket and use one typed policy surface for the complete object lifecycle."
  />
  <Card
    title="Better Upload"
    href="https://better-upload.com/docs"
    description="Own the bucket and prioritize a compact, upload-focused React integration."
  />
  <Card
    title="UploadThing"
    href="https://docs.uploadthing.com"
    description="Delegate storage infrastructure and delivery to a managed file service."
  />
  <Card
    title="Uppy"
    href="https://uppy.io/docs"
    description="Bring an existing backend and choose from a mature uploader and remote-source ecosystem."
  />
</Cards>

---

## dimah-s3 or Better Upload? [#dimah-s3-or-better-upload]

Both upload directly to an S3-compatible bucket you own. Better Upload is a
strong fit when the upload path is the product boundary: it provides concise
routes, React hooks, shadcn components, automatic multipart, and a useful set
of S3 helpers.

Choose dimah-s3 when the application also needs:

1. **Verified confirmation** — confirm takes a signed upload ticket, so it only
   finishes uploads the server started. It reads `HeadObject`, rechecks size
   and Content-Type, can check the first bytes against the type, and removes
   the object when verification or `confirmGuard` rejects it.
2. **One lifecycle policy** — the same named route and key namespace can govern
   upload, private download, proxy delivery, and server-executed deletion.
3. **Resume across reloads** — `UploadStore` can persist multipart metadata;
   after the user reselects the same local file, the client reconciles uploaded
   parts with S3.
4. **Optional application records** — `@dimah-s3/db` adds scope-based
   ownership, lifecycle state, listings with folders, and quotas without
   moving ORM behavior into the server package.

---

## dimah-s3 or UploadThing? [#dimah-s3-or-uploadthing]

UploadThing is the easier choice when you want a managed file backend and do
not want to provision a bucket, IAM policy, CORS rules, or delivery layer. It
includes hosted storage, file APIs, components, and managed public or private
URLs.

Choose dimah-s3 when storage location and infrastructure control are
requirements:

1. **Bring your own storage** — objects remain in the AWS S3, Cloudflare R2,
   MinIO, or other S3-compatible bucket configured by your application.
2. **Own the policy surface** — authentication, key generation, quotas, and
   lifecycle hooks execute in your server runtime.
3. **Avoid a file-service dependency** — there is no separate upload SaaS
   subscription, although you still pay your storage, transfer, compute, and
   maintenance costs.
4. **Use your framework directly** — adapters cover Next.js, Hono, Express,
   Fastify, Elysia, SvelteKit, Node, and standard Fetch handlers.

---

## Where DIY S3 and React Dropzone fit [#where-diy-s3-and-react-dropzone-fit]

### Raw presigned S3 URLs [#raw-presigned-s3-urls]

Building directly with the AWS SDK is a reasonable choice for one small upload
flow. You own every decision, dependency, and endpoint. As requirements grow,
you also own confirmation, key isolation, multipart coordination, retries,
download authorization, deletion, client state, and error contracts.

dimah-s3 packages those boundaries while still exposing the AWS SDK client for
application-specific operations. It intentionally does not replace general S3
APIs such as list, copy, or arbitrary tagging.

### React Dropzone [#react-dropzone]

React Dropzone handles file selection and drag-and-drop; it is not an upload
backend. `@dimah-s3/react` already uses React Dropzone for its internal file
intake, then adds route constraints, transfer state, progress, retries,
confirmation, and multipart behavior.

Use React Dropzone directly when you only need intake primitives. Use
dimah-s3's headless hooks or shadcn components when you also need the transfer
and server lifecycle.

---

## Frequently asked questions [#frequently-asked-questions]

<Accordions>

<Accordion title="Is dimah-s3 a drop-in replacement for Better Upload?">

No. The libraries use different route, hook, and response contracts, so a
migration requires adapting both server and client code.

They target the same bring-your-own-bucket model, but optimize for different
scope. Better Upload is upload-focused; dimah-s3 provides an integrated
upload-confirm-download-delete lifecycle.

</Accordion>

<Accordion title="Does Better Upload support multipart uploads?">

Yes. Better Upload can automatically use multipart when it is enabled on a
route. The relevant dimah-s3 distinction is reload-persistent metadata and
same-file resume through `UploadStore`, not multipart support by itself.

</Accordion>

<Accordion title="Is UploadThing more expensive than dimah-s3?">

Not always. dimah-s3 has no separate file-service fee, but self-hosting still
has storage, transfer, compute, and engineering costs. UploadThing bundles
managed infrastructure and support into its pricing. Compare total cost at
your file sizes, traffic, regions, and operational requirements.

</Accordion>

<Accordion title="Can I use Uppy with dimah-s3?">

Not as a drop-in replacement for `@dimah-s3/react`. Uppy's S3 plugin expects
its own signing contract, while dimah-s3 uses route names and server-owned
keys. Combining them requires a custom Uppy uploader adapter that translates
the operations without allowing the browser to choose trusted object keys.

If you only need drag-and-drop UI, use dimah-s3's headless upload hook or
optional shadcn components instead.

</Accordion>

<Accordion title="Does dimah-s3 replace the AWS SDK?">

No. dimah-s3 owns the presign upload, download, and delete lifecycle. Continue
to use the AWS SDK for application-specific operations such as list, copy,
retention, or arbitrary object tagging.

</Accordion>

</Accordions>

---

## Verify against your requirements [#verify-against-your-requirements]

Competitor capabilities change. This comparison was last reviewed on
**September 6, 2026** against the official
[Better Upload routes](https://better-upload.com/docs/routes-single),
[Better Upload helpers](https://better-upload.com/docs/helpers-server),
[UploadThing documentation](https://docs.uploadthing.com), and
[Uppy S3 documentation](https://uppy.io/docs/aws-s3).

<Cards>
  <Card
    title="Security model"
    href="/docs/server/security"
    description="Review keys, guards, verified metadata, and ownership boundaries."
  />
  <Card
    title="Provider guides"
    href="/docs/providers"
    description="Configure AWS S3, Cloudflare R2, MinIO, or another compatible service."
  />
  <Card
    title="Quickstart"
    href="/docs/quickstart"
    description="Build the first upload flow after you choose a model."
  />
</Cards>
