Store User Uploads in Your App

How to Handle User File Uploads in Your App

Handle user file uploads with a simple API. Secure storage, CDN delivery, and access controls built in.

Storing user uploads safely comes down to four responsibilities: validation, durable storage, fast delivery, and access control. Here's the architecture that handles all four without you operating storage infrastructure.

Step 1 — validate on your backend, never trust the client. Check the declared MIME type against the actual bytes (magic-number sniffing), enforce a size ceiling, and reject anything outside your allowlist. A user can rename evil.exe to cute.png; only server-side content inspection catches that.

Step 2 — mint a presigned upload URL. Your backend calls POST /v1/files/{folderId} with the file's metadata and gets back a presigned PUT URL and a file id. This is where your API key is used — as the raw Authorization header, on the server only.

Step 3 — upload the bytes. Either your backend streams them, or (better for large files) you return the presigned URL to the browser and let the client PUT directly, so a 50 MB video never tunnels through your API process. Then your backend calls POST /v1/files/confirm-upload with {ids:[id]} to finalize.

Step 4 — persist and serve. Save the returned file id (and CDN URL) in your database alongside the owning user id. For public assets like avatars, embed the permanent CDN URL directly and let the edge serve it. For anything private — invoices, ID documents, paid downloads — upload with the private flag and, when a user requests access, have your backend mint a signed URL (10-minute expiry) scoped to that one file.

Never hand the API key to the browser, and never let the client tell your backend where to store a file or which file to sign without an ownership check — that's how IDOR bugs leak other users' data.

A minimal Express handler tying it together:

js
app.post('/upload', auth, upload.single('file'), async (req, res) => {
  validate(req.file);                       // step 1
  const meta = await fl.post(`/v1/files/${FOLDER}`,
    { filesMetadata: [{ name: req.file.originalname }] }); // step 2
  const { url, id } = meta.urls[0];
  await fetch(url, { method: 'PUT', body: req.file.buffer }); // step 3
  await fl.post('/v1/files/confirm-upload', { ids: [id] });
  await db.saveUpload(req.user.id, id);      // step 4
  res.json({ id });
});

This keeps your server out of the storage business while you retain full control over who can upload what, and who can read it back.

Benefits With No Complexity

Global CDN delivery

Your files are served from 450+ edge locations worldwide.

Edge-cached worldwide

Files are cached close to your users for fast delivery.

Signed-URL security

Private files stay protected with time-limited access.

What You Get

Unlimited files

Upload as many files as you need.

Unlimited storage

There is no storage limit.

Public + Private storage

Private files are fully secured.

CDN ready links

Upload directly to 450+ edge locations worldwide.

Prepaid credits

No subscription. Pay only for the storage and bandwidth you use.

More coming soon

We have plenty of features coming!

How files.link Works

1. Upload

Create a project and upload your first file.

2. Copy

Copy the CDN link.

3. Use Anywhere

Paste and enjoy the blazing speed.

Why Developers Choose files.link

A Better Way to Store & Deliver Files

Self-managed (S3 + custom code)Firebase StorageSupabase Storagefiles.link
Built-in CDN delivery
Presigned PUT keeps bytes off your server
No storage infrastructure to operate
Private files with signed URLs
Permanent public URLs
Single REST API, no SDK required

Calculate Your Needs

Storage

0GB

Egress

0GB

CDN Bandwidth

0GB
Total: $0.000/month

Start Handling User Uploads

  • Global CDN delivery
  • Edge-cached worldwide
  • Signed-URL security
  • Unlimited files
  • Unlimited storage
  • Public + Private storage
  • No subscription — prepaid credits keep spend predictable
Start Handling User Uploads

Frequently Asked Questions

What's the recommended upload flow?
Validate the file on your backend, call POST /v1/files/{folderId} to get a presigned PUT URL and id, PUT the bytes (from your server or directly from the browser), then POST /v1/files/confirm-upload. Store the file id against the owning user in your database.
Should I let the browser upload directly?
Mint the presigned PUT URL on your backend so the API key stays secret, then let the client PUT straight to that URL. The metadata and confirm calls — which carry the key — must remain server-side. The large payload skips your API process entirely.
How do I validate against malicious uploads?
On the server, sniff the actual bytes (magic numbers) instead of trusting the declared MIME type, enforce a size limit, and use an extension/type allowlist. files.link stores files as-is, so validation is your application's job.
How do I keep some uploads private?
Upload with the private flag so no public URL is created. When a user requests access, have your backend verify ownership and mint a signed URL (10-minute expiry) for just that file id.
General Questions
Is there a subscription?
No. files.link uses prepaid credits, so storage, bandwidth, and API usage are deducted from your balance as you go. The app explains the payment step before uploads are enabled — no monthly subscription and no per-user fees.
What is files.link?
files.link is a developer-first file platform that makes it simple to store, secure, and deliver files globally. It provides signed URLs, public/private access, and an API-first design so you can integrate file delivery into any app without the usual complexity.
How does billing work?
files.link uses prepaid credits. As you use storage, bandwidth, and API requests, credits are deducted daily. When your balance runs low, we automatically recharge it using your saved card. If an auto-recharge doesn't go through, your files and links stay put — you simply update your payment method or top up manually to keep going. No monthly subscriptions — just simple usage-based pricing.
How secure is my data?
All files are encrypted at rest and in transit. You can use signed URLs for private files, control access with permissions, and rely on enterprise-grade infrastructure for data protection.

Related

files.link
Copyright © 2026
All rights reserved
ContactGuidesGlossaryStatusLegal