[Fixed]-AWS S3 presigned URL with metadata


Yes I got it working,
Basically after the signed URL is generated I need to send all the metadata and Content-Dispostion in header along with the signed URL.
For eg: My metadata dictionary is {‘test’:’test’} then I need to send this metadata in header i.e. x-amz-meta-test along with its value and content-dispostion to AWS


I was using createPresignedPost and for me I got this working by adding the metadata I wanted to the Fields param like so :-

const params = {
    Expires: 60,
    Bucket: process.env.fileStorageName,
    Conditions: [['content-length-range', 1, 1000000000]], // 1GB
    Fields: {
        'Content-Type': 'application/pdf',
        key: strippedName,
        'x-amz-meta-pdf-type': pdfType,
        'x-amz-meta-pdf-id': pdfId,

As long as you pass the data you want, in the file’s metadata, to the lambda that you’re using to create the preSignedPost response then the above will work. Hopefully will help someone else…


I found the metadata object needs to be key/value pairs, with the value as a string (example is Nodejs lambda):

const AWS = require('aws-sdk');
const s3 = new AWS.S3();

exports.handler = async (event) => {
    const { key, type, metadata } = JSON.parse(event.body);

    // example
    /*metadata: {
      foo: 'bar',
      x: '123',
      y: '22.4213213'

    return await s3.getSignedUrlPromise('putObject', {
        Bucket: 'the-product-uploads',
        Key: key,
        Expires: 300,
        ContentType: type,
        Metadata: metadata

Then in your request headers you need to add each k/v explicitly:

await fetch(signedUrl, {
      method: "PUT",
      headers: {
        "Content-Type": fileData.type,
        "x-amz-meta-foo": "bar",
        "x-amz-meta-x": x.toString(),
        "x-amz-meta-y": y.toString()
      body: fileBuffer


In boto, you should provide the Metadata parameter passing the dict of your key, value metadata. You don’t need to name the key as x-amz-meta as apparently boto is doing it for you now.

Also, I didn’t have to pass the metadata again when uploading to the pre-signed URL:

params = {'Bucket': bucket_name, 
          'Key': object_key, 
          'Metadata': {'test-key': value}

response = s3_client.generate_presigned_url('put_object',

I’m using a similar code in a lambda function behind an API


Leave a comment