Astro File Upload
Upload Files from Astro API Routes with fetch
Upload files from Astro API routes with fetch. No SDK, REST API, CDN delivery, prepaid credits.
Astro is static-first, but its API endpoints (src/pages/api/*.ts exporting POST) and on-demand server routes give you a place to run server code — which is exactly what a secure file upload needs. files.link plugs into an Astro endpoint with three fetch calls: no aws-sdk, no adapter-specific storage binding, and the same code works whether you deploy with the Node, Vercel, Netlify, or Cloudflare adapter.
The Astro-specific gotcha is environment variables. Astro exposes anything prefixed PUBLIC_ to the client bundle, so your API key must be referenced as a server-only variable (import.meta.env.FILESLINK_KEY with no PUBLIC_ prefix) and used only inside the endpoint, never in a .astro component's frontmatter that gets serialized.
// src/pages/api/upload.ts
import type { APIRoute } from 'astro';
export const POST: APIRoute = async ({ request }) => {
const form = await request.formData();
const file = form.get('upload') as File;
const key = import.meta.env.FILESLINK_KEY;
const r1 = await fetch(`https://api.files.link/v1/files/${import.meta.env.FOLDER_ID}`, {
method: 'POST',
headers: { Authorization: key, 'Content-Type': 'application/json' },
body: JSON.stringify({ filesMetadata: [{ name: file.name, size: file.size, type: file.type }] }),
});
const slot = (await r1.json()).urls[0];
await fetch(slot.url, { method: 'PUT', body: file });
await fetch('https://api.files.link/v1/files/confirm-upload', {
method: 'POST',
headers: { Authorization: key, 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: [slot.id] }),
});
return new Response(JSON.stringify({ id: slot.id }), {
headers: { 'Content-Type': 'application/json' },
});
};The powerful part for an Astro project is hybrid rendering: keep your site output: 'static' for speed and SEO, but mark the upload endpoint as prerender = false so only that route runs on-demand server-side. You get a fully static marketing or docs site plus a real upload backend, without splitting into two deployments. The CDN URL you get back drops straight into an <img> or <video> tag rendered at build or request time.
The Authorization header takes the raw key, files come back as CDN URLs with per-file visibility, storage is encrypted at rest, and billing is prepaid credits with no metered egress invoice.
Benefits With No Complexity
Global CDN delivery
Edge-cached worldwide
Signed-URL security
What You Get
Unlimited files
Unlimited storage
Public + Private storage
CDN ready links
Prepaid credits
More coming soon
How files.link Works
1. Upload
2. Copy
3. Use Anywhere
Why Developers Choose files.link
A Better Way to Store & Deliver Files
| AWS S3 (aws-sdk) | Netlify Blobs | files.link | |
|---|---|---|---|
| Works in Astro API routes (no SDK) | |||
| Same code across all SSR adapters | |||
| Hybrid static + on-demand endpoint | |||
| Global CDN delivery on every file | |||
| Prepaid credits (no surprise bills) |
Calculate Your Needs
Storage
Egress
CDN Bandwidth
Wire Up Astro 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