Download a pdf uploaded on a database

Hi, I'm new here.
I've made an uploader for PDF files, the I've made a table to show the uploaded files and I want do inserto a download buutton for each file.
I've inserted this in a JS query:


table1: the table
nome: the name of the file

Hey @eliodalte! I just want to check - is this a setup that's working for you or are you running into any particular issues with it?

1 Like

This setup is not working for me. The result is an empty PDF.

I see, your use of utils.downloadFile looks all good. Would you mind sharing the value of and It can be helpful to look in the state tab of either the left panel or your debug window. Based on your description I'd expect to see something like this:

1 Like

I think that the problem is, vause I don't have this one. My PDFs are uploaded as a BLOB value, so I thought that with .base64PDF I would convert it as a PDF again. So, what should I do?

Hmm.. :thinking: how exactly are you getting the PDFs into Retool? Typically Blobs can't be passed through the model without some kind of conversion. Knowing what that is might be key to figuring out how to convert it to base 64.

1 Like

Got it! Thanks for that context.

To start, it might be easier if you pass {{ fileInput1.value[0] }} to your upload query. File inputs typically store their values in an array so accessing it with [0] will make sure you're uploading just the base64 value and not an array containing the base64 string.

(Replace date in the image above with nome).

Since Retool is uploading a base64 string to your MySQL DB but the column type is blob there's some conversion that goes on in the background. We can undo this in your get query with something like:

select nome, convert(file using utf8) as file from Menu;

From there you should be able to use


If it's important that you upload specifically an array of file data you'll instead want to use:

utils.downloadFile({base64Binary: JSON.parse([0]},,'pdf');

Alternatively, there's a more complex JavaScript solution where you both convert and download the file using the same script:

const bufferData =;
const binArrayFile = new Uint8Array(bufferData, 1, bufferData.length / 2);
let str = "";
for (let i = 0; i < binArrayFile.length; i++) {
  str += String.fromCharCode(parseInt(binArrayFile[i]));

//use this when uploading with {{ fileInput1.value[0] }}
utils.downloadFile({base64Binary: str},, "pdf");

//use this when uploading with {{ fileInput1.value }}
const base64File = JSON.parse(str)[0];
utils.downloadFile({base64Binary: base64File},, "pdf");

Let me know if that helps!


Thank you very much! <3

Hi guys, relatively new to Retool.
I created a form where users can upload pdf. I put some validation
But when I call fileInput2.value[0], it returns a string of over 5000 characters. and it can't fit into a cell. Where do I go from here, pls?

Hey @Chilaka!

If you're trying to fit it into a table cell it may be best to grab a thumbnail that you can use in an image column. Does the source of your PDF have thumbnail previews as well?

If not, you might be able to use a third-party library (docs here) to generate them, but that's something I've yet to try and be successful with :thinking:

Hi, @Kabirdas Thank you.
I have integrated to GCS - the files are uploaded this way and it seems fine.

I want to create a download button -- that runs a 'download file' query from the gcs. But I need a file key.

Can I get the file key immediately after upload and return it in a column

When you upload a file to GCS it should return metadata for that file including the file's name and type as well as a signed url you can use to access the file.

You should be able to use the file name to access the file data in a separate GCS query:

How you would add this to your table as a column depends a bit on how you're getting your table data though. As mentioned in this thread it's likely best to update the data source for your table directly with a separate query.

If you have additional questions about how to do that we'll be happy to help out, would you mind creating a new thread? It looks as though things are getting away from the original topic here.