FileHutch

Migrate from Uploadcare

The same upload flow, with the bytes in your account

Uploadcare and Filestack do uploading well and the widgets are good. The thing to check before you commit is where the file ends up, and whose URL you are about to store.

Before and after

The same attachment, both ways

Uploadcare

// The identifier only means something inside their system
const file = await uploadFile(input.files[0], { publicKey: "…" })
await api.patch(`/users/${id}`, { avatar: file.uuid })

FileHutch

// The ID resolves against a bucket you can point somewhere else
const file = await hutch.upload(input.files[0], { policy: "avatars" })
await api.patch(`/users/${id}`, { avatar_file_id: file.id })

Why people move

What changes, and why it matters

The file UUID is theirs
It resolves through their infrastructure, so it is only meaningful while you are a customer. A FileHutch ID is yours and points at a bucket you can own.
Delivery is their CDN or nothing
That is fine, and it is fast. It is also the part you cannot replace without replacing the file IDs too.
Priced per file and per upload
Predictable when traffic is, expensive when a customer bulk-imports. FileHutch prices storage, which is the thing that actually accumulates.
Widget first, API second
If you are building your own upload UI — and most apps eventually do — you are paying for a widget you replaced.

Side by side

Where each one is stronger

Aspect Uploadcare FileHutch
File identifier Their UUID Your ID, your bucket
Where bytes live Their storage Yours, or our managed bucket
Delivery Their CDN Your bucket, behind your zone if you want
Pricing unit Files and uploads Stored gigabytes
Upload UI Hosted widget A Stimulus controller, or your own
Audit Limited Every action, attributed

The move, in order

Every step is reversible until the last one.

  1. 1

    Create a project and an upload policy

    The policy carries the types, the size cap and the visibility, so the browser cannot ask for more than you allowed.

  2. 2

    Connect your own bucket

    This is the point of the exercise. Do it before the backfill so you only copy the bytes once.

  3. 3

    Swap the widget for the SDK

    The TypeScript SDK does direct-to-bucket uploads with progress. If you had already replaced the widget, this step is nothing.

  4. 4

    Backfill by streaming each file across

    Read from their CDN, write through the upload API, store the new ID alongside the old UUID.

  5. 5

    Flip reads, then delete the old account

    Keep both columns until the fallback stops firing.

What does not change

  • Direct-to-storage uploads with progress events
  • Client-side validation before the byte leaves the browser
  • A resize on the way out

When to stay where you are

Their upload widget handles more edge cases than ours does — camera capture, cloud-drive imports, and a lot of accessibility work. If the widget is doing real work for you, replacing it is a cost, not a saving.

Try the move on one attachment first.

The free plan is enough to migrate a single model and see whether the rest is worth it.