All posts
June 11, 2026 · Snapdock

How Do I Add File Downloads to My App?

You built something with Claude, ChatGPT, Bolt, or Lovable and users need to be able to download files. Maybe a generated PDF report. Maybe a CSV export of…

You built something with Claude, ChatGPT, Bolt, or Lovable and users need to be able to download files. Maybe a generated PDF report. Maybe a CSV export of their data. Maybe a document they previously uploaded that they want to retrieve. File downloads seem simple but have a few non-obvious implementation details that trip up most first attempts. Here is exactly how to do it correctly.

The Two Types of File Downloads

Static files: files that exist already and do not change. A PDF user manual, a template document, a sample CSV. These can be served directly from your hosting platform’s CDN.

Dynamic files: files generated on demand for a specific user. A PDF of their invoice, a CSV export of their data, a report customised to their account. These need to be generated by your backend at the moment the user requests them.

Downloading Static Files

For files that already exist and do not change, the simplest approach is to store them in your hosting platform’s public folder or in cloud storage like Supabase Storage or AWS S3 and link directly to them.

html

<a href="/downloads/user-guide.pdf" download>Download User Guide</a>

The download attribute on an anchor tag tells the browser to download the file rather than navigate to it. Without this attribute, PDFs open in the browser instead of downloading.

For files in Supabase Storage, get the public URL from the Supabase dashboard and use that as the href. Ask your AI: “Can you add a download button to my app that lets users download [describe the file]? The file is stored at [URL or location].”

Generating and Downloading Dynamic Files

For files generated on demand, your backend creates the file and sends it to the user’s browser with headers that trigger a download.

CSV export (most common): your backend queries the user’s data, formats it as CSV, and sends it with a Content-Disposition header that tells the browser to download it.

Ask your AI: “Can you add a button to my app that exports the user’s [describe the data, e.g. orders, records] as a CSV file they can download? Generate the CSV on the backend and trigger a download.”

PDF generation: PDFs are more complex because they require a library to generate them. Common Python libraries include ReportLab and WeasyPrint. In JavaScript, libraries like Puppeteer or pdfkit handle PDF generation.

Ask your AI: “Can you add a button that generates a PDF of [describe what the PDF should contain, e.g. the user’s invoice, their report] and downloads it? Use [Python/JavaScript] and an appropriate PDF library.”

Downloading Files From Cloud Storage With Access Control

If your files are stored in cloud storage and some files should only be accessible to specific users (not publicly accessible to anyone with the URL), you need signed URLs.

A signed URL is a temporary URL that includes authentication information, granting access to a specific file for a limited time. After the URL expires, it no longer works.

Ask your AI: “My files are stored in Supabase Storage in a private bucket. Can you generate a signed URL when a logged-in user requests a download, so the file is only accessible to authorised users?”

Progress Indicators for Large Downloads

For large files, show a progress indicator so users know the download is happening. The browser handles this automatically for direct file downloads, showing progress in the download bar. For files generated on demand, consider showing a loading state on the download button while the file is being generated.

The One Thing to Remember

File downloads come in two types: static files that already exist (link directly using an anchor tag with download attribute) and dynamic files generated on demand (generate on the backend and send with Content-Disposition headers). For private files in cloud storage, use signed URLs that expire so only authorised users can access them.


Want your file-serving app running reliably in production? → Snapdock

New here? These might help: How do I add file uploads to my app? → What is a .env file? Why your app needs one and how to use it. →