File paths

By default this addon will give every upload a unique key in your S3 bucket. If you would like to customize the key you can do so by configuring the API route.

// pages/api/s3-upload.js
import { APIRoute } from "next-s3-upload";

export default APIRoute.configure({
  key(req, filename) {
    return `my/uploads/path/${filename}`;
  }
});

The key function can return a promise if you need to do something async.

// pages/api/s3-upload.js
import { APIRoute } from "next-s3-upload";

export default APIRoute.configure({
  async key(req, filename) {
    let path = await getPath();
    return `${path}/${filename}`;
  }
});

File names

The AWS guidelines recommend using a specific subset of characters for key names. This library has a sanitizeKey() function to remove any characters that could cause problems when stored on S3.

// pages/api/s3-upload.js
import { APIRoute, sanitizeKey } from "next-s3-upload";

export default APIRoute.configure({
  key(req, filename) {
    return `safe-file-name/${sanitizeKey(filename)}`;
  }
});

This function is useful if you are accepting uploads for non-english filenames.

File extensions

If you set up your IAM user to only upload specific file extensions then your key function must return a path ending with one of your allowed extensions.

If the key function returns a path that does not include an allowed extension then your upload will fail with an access denied error.

Data from React

You can pass data from your React app to the key function using uploadToS3 options.

In the example below, we pass a projectId from the frontend using the endpoint.request.body option.

// Frontend component
function Component() {
  let { uploadToS3 } = useS3Upload();

  let handleSubmit = async () => {
    // You can pass extra data using `endpoint.request.body`

    await uploadToS3(file, {
      endpoint: {
        request: {
          body: {
            projectId: 123
          }
        }
      }
    });
  };
}

Now the key function can read the passed projectId from req.body.projectId.

// pages/api/s3-upload.js
import { APIRoute } from "next-s3-upload";

export default APIRoute.configure({
  async key(req, filename) {
    let projectId = req.body.projectId; // 123

    return `projects/${projectId}/${filename}`;
  }
});

All data that needs to be passed from the frontend should be sent under the endpoint.request.body object, since that data will get serialized into the request's body.

You can pass any data you'd like here, as long as it's serializable into JSON.

Headers

The uploadToS3 function can also add request headers that can be used by the key function.

// Frontend component
function Component() {
  let { user } = useAuth();
  let { uploadToS3 } = useS3Upload();

  let handleSubmit = async () => {
    let authToken = await user.getAuthToken();

    await uploadToS3(file, {
      endpoint: {
        request: {
          headers: {
            authorization: authToken
          }
        }
      }
    });
  };
}

And the authorization header can be read using req.headers.authorization.

// pages/api/s3-upload.js
import { APIRoute } from "next-s3-upload";

export default APIRoute.configure({
  async key(req, filename) {
    let user = await getUserFromAuthToken(req.headers.authorization);

    return `users/${user.id}/${filename}`;
  }
});