Flask File Upload

Upload Files from Flask Routes with the requests Library

Upload files from Flask routes with requests. No SDK, REST API, CDN delivery, prepaid credits.

A Flask upload route does not need flask-uploads, Flask-Reuploaded, or a hand-rolled boto3 S3 wrapper. The requests library — already in almost every Flask project — covers the entire files.link flow in three calls. You take the incoming file off request.files, push it to a presigned URL, confirm it, and hand back a CDN link. No bucket, no IAM user, no SigV4.

The browser sends the file as multipart/form-data, which Flask parses into request.files['upload'] as a Werkzeug FileStorage. You read its bytes once and PUT them to the presigned URL — the presigned PUT wants the raw body, not a re-wrapped multipart form, which is the most common mistake people make when porting from an S3 example.

python
import os, requests
from flask import Flask, request, jsonify

app = Flask(__name__)
KEY = os.environ['FILESLINK_KEY']
BASE = 'https://api.files.link'
FOLDER = os.environ['FILESLINK_FOLDER']

@app.post('/upload')
def upload():
    f = request.files['upload']
    data = f.read()
    r1 = requests.post(f'{BASE}/v1/files/{FOLDER}',
        headers={'Authorization': KEY},
        json={'filesMetadata': [{'name': f.filename, 'size': len(data), 'type': f.mimetype}]})
    slot = r1.json()['urls'][0]

    requests.put(slot['url'], data=data, headers={'Content-Type': f.mimetype})

    requests.post(f'{BASE}/v1/files/confirm-upload',
        headers={'Authorization': KEY}, json={'ids': [slot['id']]})
    return jsonify(id=slot['id'])

The Authorization header takes the raw API key — no Bearer prefix. Keep the key in os.environ (loaded via python-dotenv in dev) and out of source control. For larger uploads, avoid f.read() loading the whole file into memory: stream from f.stream in chunks, or move the three-call flow into a Celery task so the request returns immediately and the user is not blocked on a slow PUT.

Set MAX_CONTENT_LENGTH in your Flask config so oversized bodies are rejected before they reach the route, and validate f.mimetype against an allowlist rather than trusting the client-supplied filename extension. Registering the route inside a Blueprint keeps the upload logic reusable across multiple Flask apps that share the same files.link folder. If you have migrated to async Flask or Quart, swap requests for httpx.AsyncClient and await each call — the sequence is identical.

Files come back as CDN-backed URLs, visibility is set per file, storage is encrypted at rest, and you pay from prepaid credits rather than a metered egress bill.

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

flask-uploads + S3 (boto3)Cloudinary (python-cloudinary)files.link
No Flask extension to install (just requests)
No boto3 / IAM credential chain
Global CDN delivery on every file
Per-file public vs signed visibility
Prepaid credits (no surprise bills)

Calculate Your Needs

Storage

0GB

Egress

0GB

CDN Bandwidth

0GB
Total: $0.000/month

Wire Up Flask File 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 Uploading from Flask

Frequently Asked Questions

Do I need flask-uploads or boto3?
No. Flask already parses the upload into request.files, and the three files.link calls go through the requests library. There is no extension to register and no boto3 credential chain to configure.
How do I read the uploaded file in a Flask route?
Grab it with request.files['upload'] — a Werkzeug FileStorage. Call .read() for small files or stream from .stream for large ones, then PUT the raw bytes to the presigned URL. Do not re-wrap it as multipart.
How do I avoid blocking the request on a slow upload?
Move the three-call flow into a Celery task. The route enqueues the job and returns immediately; the worker performs the metadata POST, presigned PUT, and confirm POST in the background.
Can I use this with async Flask or Quart?
Yes. Replace requests with httpx.AsyncClient and await each of the three calls. The endpoints and request shapes are identical to the synchronous version.
Where does the API key go?
Read it from os.environ['FILESLINK_KEY'] (load via python-dotenv in development) and send it as the raw value in the Authorization header. Never hardcode it in app config that lands in git.
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