Bubble stores uploaded files as URLs, so downloading requires either opening the URL in a new tab or using JavaScript to force a browser download. This tutorial covers both approaches: the simple open-in-new-tab method and the forced download method using the Toolbox plugin, plus how to generate temporary download links.
Overview: Handling File Downloads in Bubble
When users upload files to your Bubble app, those files are stored as URLs on Bubble's servers. Getting users to download those files requires a workflow that either opens the URL in a new tab or triggers a forced download. This tutorial covers both methods so you can provide the right download experience for your app.
Prerequisites
- A Bubble app with files already stored in the database
- Basic understanding of Bubble workflows
- The Toolbox plugin installed (optional, for forced downloads)
Step-by-step guide
Add a download button that opens the file in a new tab
Add a download button that opens the file in a new tab
This is the simplest approach. On your page, add a Button element labeled Download. In its workflow, add the action Navigation → Open an external website. For the URL, use the dynamic expression that points to your file field — for example, Current cell's Document's attachment. Check the Open in a new tab option. Images and PDFs will typically display in the browser, while other file types will trigger a download automatically.
Pro tip: Append ?dl= to the end of the file URL to hint to some browsers that the file should be downloaded rather than displayed.
Expected result: Clicking the button opens the file in a new browser tab. PDFs and images display inline; other files download automatically.
Force a download using the Toolbox plugin's Run JavaScript action
Force a download using the Toolbox plugin's Run JavaScript action
Install the Toolbox plugin from the Plugins tab if you have not already. In your download button's workflow, add the action Plugins → Run JavaScript. Enter this code: var link = document.createElement('a'); link.href = 'DYNAMIC_URL'; link.download = 'DYNAMIC_FILENAME'; document.body.appendChild(link); link.click(); document.body.removeChild(link); Replace DYNAMIC_URL with the file's URL and DYNAMIC_FILENAME with the desired filename. Use Bubble's dynamic data insertion to populate these values.
1var link = document.createElement('a');2link.href = 'https://your-app.bubbleapps.io/file/abc123';3link.download = 'document.pdf';4document.body.appendChild(link);5link.click();6document.body.removeChild(link);Pro tip: The forced download approach may not work for cross-origin files in all browsers. Test across Chrome, Safari, and Firefox.
Expected result: Clicking the button triggers an immediate file download to the user's device instead of opening in the browser.
Create download links inside a Repeating Group
Create download links inside a Repeating Group
If you display files in a Repeating Group, add a Link element inside each cell. Set the Link destination to External URL and use Current cell's Document's attachment as the dynamic URL. Set the link text to something like the file title or Download File. Enable Open in a new tab. This creates a clickable download link for every file in the list without needing a separate workflow.
Expected result: Each row in the Repeating Group has a clickable link that downloads or opens the associated file.
Track download counts for each file
Track download counts for each file
Add a number field called download_count to your file Data Type. In the download button's workflow, add an action before or after the download: Make Changes to Current cell's Document, setting download_count to Current cell's Document's download_count + 1. Display this count in a Text element inside the Repeating Group cell to show how many times each file has been downloaded.
Expected result: Every download increments a counter, and users can see how many times each file has been downloaded.
Complete working example
1FILE DOWNLOAD WORKFLOW SUMMARY2===============================34METHOD 1: Open in New Tab5 Button: DownloadButton6 Workflow: When DownloadButton is clicked7 Action: Open an external website8 → URL: Current cell's Document's attachment9 → Open in new tab: yes1011METHOD 2: Forced Download (Toolbox plugin)12 Button: DownloadButton13 Workflow: When DownloadButton is clicked14 Action 1: Run JavaScript15 → Script: 16 var link = document.createElement('a');17 link.href = '[Current cell's Document's attachment]';18 link.download = '[Current cell's Document's title]';19 document.body.appendChild(link);20 link.click();21 document.body.removeChild(link);22 Action 2: Make Changes to Current cell's Document23 → download_count = download_count + 12425METHOD 3: Link Element in Repeating Group26 Link element inside RG cell:27 → Destination: External URL28 → URL: Current cell's Document's attachment29 → Open in new tab: yes30 → Text: Current cell's Document's title3132DATA STRUCTURE:33 Document Data Type:34 - title (text)35 - attachment (file)36 - download_count (number, default: 0)37 - uploaded_by (User)Common mistakes when building file downloads in Bubble
Why it's a problem: Expecting all files to auto-download when opened in a new tab
How to avoid: Use the Toolbox Run JavaScript forced download method for file types that browsers typically display inline
Why it's a problem: Not handling missing or deleted files
How to avoid: Add a condition to hide the download button when the file field is empty, and periodically clean up orphaned file references
Why it's a problem: Making file URLs publicly accessible without access controls
How to avoid: Set Privacy Rules on the Data Type containing the file field to restrict which users can view the file URL
Best practices
- Use the Open in new tab method for simplicity unless you specifically need forced downloads
- Add Privacy Rules to control who can access file URLs in your database
- Track download counts if analytics are important for your use case
- Show the file type and size next to the download button for better user experience
- Test downloads across multiple browsers since download behavior varies
- Use descriptive filenames in the forced download method so users know what they saved
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a Bubble.io app with files stored in the database. I need to add download buttons that work for all file types including PDFs and images. How do I force a browser download instead of opening the file in a new tab?
Add download functionality to my file list. I have a Repeating Group showing documents. Each row needs a download button that forces the browser to download the file instead of opening it.
Frequently asked questions
Why does my PDF open in the browser instead of downloading?
Most browsers display PDFs inline by default. Use the Toolbox plugin's Run JavaScript action with the link.download attribute to force a download, or append ?dl=1 to the URL.
Can I generate a temporary or expiring download link?
Bubble does not natively support expiring URLs. You can build a workaround by creating a backend workflow that checks a token and timestamp before redirecting to the file URL.
Are file URLs permanent?
Yes, as long as the file exists in your Bubble app. File URLs remain valid unless you manually delete the file from the File Manager or delete the app.
How do I handle large file downloads without timeouts?
Bubble serves files directly from its CDN, so large files should download without timeout issues. If users report slow downloads, the bottleneck is likely their internet connection, not Bubble.
Can I restrict downloads to logged-in users only?
Yes. Set Privacy Rules on the Data Type so the file field is only visible to logged-in users. Without access to the URL, they cannot download the file. For enterprise-level access control, RapidDev can help design secure file access systems.
Can I let users preview a file before downloading?
For images, use an Image element with the file URL as the source. For PDFs, use an HTML element with an iframe pointing to the file URL. Other file types generally cannot be previewed in the browser.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation