vohzd.com

Uploading Large Files to S3 with Multipart Chunking

1 min read

Here's how to upload large files to an S3 bucket using multipart chunking (5MB blobs at a time). The advantage is your server won't run out of RAM when someone uploads a massive file.

Node.js Backend

const express = require("express");
const companion = require("@uppy/companion");
const port = 1337;
const app = express();

app.use("/presign", companion.app({
  providerOptions: {
    s3: {
      endpoint: S3_URL_ENDPOINT,
      getKey: (req, filename) => `${req.body.metadata.folderName}/${filename}`,
      key: YOUR_API_KEY,
      secret: YOUR_API_SECRET,
      bucket: YOUR_BUCKET_NAME,
      region: YOUR_REGION,
    },
  },
  server: { serverUrl: `localhost:${port}` },
}));

app.listen(port, () => {
  console.log(`working on ${port}`);
});

Vue Frontend

<template>
  <div class="relative">
    <div class="uppy"></div>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import Uppy from "@uppy/core";
import Dashboard from "@uppy/dashboard";
import AwsS3Multipart from "@uppy/aws-s3-multipart";
import "@uppy/core/dist/style.min.css";
import "@uppy/dashboard/dist/style.min.css";

const uppy = ref(null);

onMounted(() => {
  uppy.value = new Uppy({
    debug: false,
    autoProceed: false,
    meta: { folderName: "somefoldername" },
  });

  uppy.value
    .use(Dashboard, {
      target: ".uppy",
      inline: true,
      replaceTargetContent: true,
      showProgressDetails: true,
      height: 470,
      browserBackButtonClose: true,
    })
    .use(AwsS3Multipart, {
      companionUrl: `${import.meta.env.VITE_SERVER_ENDPOINT}/presign`,
      limit: 5,
    })
    .on("complete", (result) => {
      console.log("Upload complete:", result);
    });
});
</script>

The backend handles presigning S3 URLs, and the frontend uses Uppy's dashboard to chunk everything up. No faffing about with manual multipart logic, Uppy sorts it all out.