FastAPI File Upload

Upload Files from FastAPI Async Routes with httpx

Upload files from FastAPI async routes with httpx. No SDK, REST API, CDN delivery, prepaid credits.

FastAPI is async to its core, so the right way to upload a file is with an async HTTP client — httpx.AsyncClient — not by wrapping a synchronous boto3 call in a thread pool. files.link is three awaited calls that fit cleanly into FastAPI's event loop: POST metadata, PUT bytes, POST confirm. No boto3, no aiobotocore, no AWS credentials chain, no bucket.

FastAPI gives you the incoming file as an UploadFile, a SpooledTemporaryFile-backed object with async read methods, so you can move data without blocking the loop:

python
import os, httpx
from fastapi import FastAPI, UploadFile

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

@app.post('/upload')
async def upload(file: UploadFile):
    data = await file.read()
    async with httpx.AsyncClient() as client:
        r1 = await client.post(f'{BASE}/v1/files/{FOLDER}',
            headers={'Authorization': KEY},
            json={'filesMetadata': [{'name': file.filename, 'size': len(data), 'type': file.content_type}]})
        slot = r1.json()['urls'][0]

        await client.put(slot['url'], content=data, headers={'Content-Type': file.content_type})

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

Reuse a single httpx.AsyncClient across requests (create it in a lifespan handler and store it on app.state) so connections are pooled instead of re-dialed on every upload. For uploads where you do not want the client waiting on the transfer, hand the three-call flow to BackgroundTasks so the response returns the moment metadata is accepted; for retry guarantees, push it to a task queue like arq or Celery instead.

Note that file.read() with no argument loads the whole file into memory — for large media, read in chunks with await file.read(chunk_size) and use the multipart endpoint, PUTting each part to its own presigned URL as you stream.

The Authorization header takes the raw API key (no Bearer prefix), sourced from pydantic-settings BaseSettings reading your .env and injected via Depends. files.link returns CDN-backed URLs with per-file visibility, storage encrypted at rest, and prepaid-credit billing — async upload without the boto3 footprint or a surprise 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

AWS S3 (boto3 / aiobotocore)Cloudinary (python-cloudinary)files.link
Async-native with httpx (no thread-pool wrap)
No boto3 / AWS credentials chain
Reusable pooled AsyncClient
Global CDN delivery on every file
Prepaid credits (no surprise bills)

Calculate Your Needs

Storage

0GB

Egress

0GB

CDN Bandwidth

0GB
Total: $0.000/month

Wire Up FastAPI 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 FastAPI

Frequently Asked Questions

Why httpx instead of boto3 in FastAPI?
boto3 is synchronous, so calling it from an async route blocks the event loop unless you wrap it in a thread pool. httpx.AsyncClient is natively async, so the three files.link calls await cleanly without blocking other requests.
How do I reuse the HTTP client across requests?
Create one httpx.AsyncClient in a lifespan handler, store it on app.state, and reuse it. That pools TCP connections instead of opening and closing one per upload, which matters under load.
How do I upload without making the client wait?
Accept the UploadFile, then enqueue the three-call flow with FastAPI's BackgroundTasks so the response returns immediately. If you need retries, hand the work to arq or Celery instead.
How do I handle very large files?
Avoid await file.read() with no argument — it loads the whole file into memory. Read in chunks with await file.read(chunk_size) and use the multipart endpoint, PUTting each part to its presigned URL as you stream.
Where do I configure the API key?
Use pydantic-settings BaseSettings to read FILESLINK_KEY from .env, inject it with Depends, and send it as the raw Authorization header value with no Bearer prefix.
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