#6536·uppy

Support S3 POST policy-based presigned uploads in @uppy/aws-s3 v6

Author: danielchristopher513Created Sep 8, 2026Updated Sep 15, 2026
LabelsFeatureAWS S3

Initial checklist

  • I understand this is a feature request and questions should be posted in the Community Forum
  • I searched issues and couldn’t find anything (or linked relevant results below)

Problem

In Uppy v6, @uppy/aws-s3 no longer appears to support direct-to-S3 uploads using an S3 POST policy / presigned POST.

This is a meaningful limitation for applications that intentionally use S3 POST rather than presigned PUT URLs.

S3 supports both upload mechanisms:

Presigned PUT URL Presigned POST using a policy and form fields such as key, policy, x-amz-algorithm, x-amz-credential, x-amz-signature, etc.

The latter is useful when the server needs to enforce upload constraints through the signed policy, such as key prefixes, content length ranges, content type, and other form conditions.

Solution

It would be useful for @uppy/aws-s3 to support S3 POST policy uploads as a first-class option.

For example, the backend could return something conceptually like:

{
  url: 'https://my-bucket.s3.amazonaws.com',
  fields: {
    key: 'uploads/${filename}',
    policy: '...',
    'x-amz-algorithm': 'AWS4-HMAC-SHA256',
    'x-amz-credential': '...',
    'x-amz-date': '...',
    'x-amz-signature': '...',
    'Content-Type': 'image/jpeg'
  }
}

Uppy could then construct a multipart/form-data request and POST the file directly to S3. Ideally this could integrate with the existing Uppy upload lifecycle, including:

  • progress reporting
  • concurrency
  • retry/error handling
  • cancellation
  • metadata
  • upload completion events

Why POST support is important

Presigned POST is not simply an alternative spelling of presigned PUT. The two mechanisms provide different capabilities.

A presigned POST allows the server to sign a policy containing conditions that S3 itself validates. For example:

{
  "conditions": [
    ["content-length-range", 0, 104857600],
    ["starts-with", "$key", "uploads/"],
    ["starts-with", "$Content-Type", "image/"]
  ]
}

This can be useful for applications that don't want to expose broader S3 permissions or rely entirely on PUT URL generation.

Possible API

One possible API could be something along the lines of:

uppy.use(AwsS3, {
  async getUploadParameters(file) {
    return {
      method: 'POST',
      url: 'https://my-bucket.s3.amazonaws.com',
      fields: {
        key: 'uploads/...',
        policy: '...',
        'x-amz-algorithm': '...',
        'x-amz-credential': '...',
        'x-amz-date': '...',
        'x-amz-signature': '...'
      }
    }
  }
})

The exact API is of course up to the maintainers; the important part is having a supported way to perform S3 policy-based POST uploads directly from the browser.

Alternatives

Using PUT presigned URLs is possible, but changing from POST to PUT is not always trivial for an existing backend architecture because the authorization model and signed constraints are different.

Using @uppy/xhr-upload with a custom uploader can also work, but that means losing the dedicated S3 integration and having to reimplement behavior that @uppy/aws-s3 already provides.