Next.js S3 Upload

repository·master·Indexed 20 days ago

https://github.com/ryanto/next-s3-upload

A utility library for streamlining file uploads from Next.js applications directly to Amazon S3 or S3-compatible hosts. It provides the useS3Upload hook, a FileInput component, and the getImageData helper for extracting image dimensions. Supports configuration via environment variables or APIRoute.configure(), and includes guidance for integrating with next/image.

Tokens
16K
Snippets
53
Records
69
Agent score
69%

What's inside next-s3-upload

  1. Compare AWS SDK vs. Presigned Uploads

    master

    When choosing an upload method in next-s3-upload, consider the following trade-offs:

    AWS SDK (useS3Upload)

    • Pros: Supports large files (via multipart uploads), handles failures and retries automatically, and is the recommended approach for most use cases.
    • Cons: Requires loading the AWS SDK JavaScript library on the frontend, increasing bundle size.

    Presigned Uploads (usePresignedUpload)

    • Pros: No AWS SDK required on the client; smaller bundle size; compatible with non-AWS S3-compatible hosts.
    • Cons: Strict 1GB limit (S3 will reject files over 1GB); lacks the automatic multipart/retry features of the SDK.
  2. How the useS3Upload workflow works

    master

    The standard upload workflow using useS3Upload follows these steps:

    1. Trigger Selection: The user clicks a UI element (like a button) that calls openFileDialog.
    2. File Selection: The browser opens a file dialog. Once a file is selected, the onChange handler of the <FileInput /> component is triggered.
    3. Upload: The handler calls uploadToS3(file). This function performs the upload to S3.
    4. Completion: Upon a successful upload, uploadToS3 returns an object containing the url of the uploaded file, which can then be used in the application (e.g., to display an image).
  3. Pass data from React to the S3 key function

    master

    You can pass custom data from your frontend component to the API route's key function by using the endpoint.request.body option within uploadToS3. This data is serialized into the request body and can be accessed via req.body in your API route. This is useful for including metadata like projectId in the file path.

    // Frontend component
    function Component() {
      let { uploadToS3 } = useS3Upload();
    
      let handleSubmit = async () => {
        await uploadToS3(file, {
          endpoint: {
            request: {
              body: {
                projectId: 123
              }
            }
          }
        });
      };
    }
    
    // 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}`;
      }
    });
  4. Track upload progress with the useS3Upload hook

    master

    The useS3Upload hook returns a files array that tracks the upload status of all files currently being processed. Each object in the files array contains a progress property, which is a number between 0 and 100 that updates continuously as the file uploads. You can map over this array to render a UI that displays the real-time progress percentage for each file.

    import { useS3Upload } from "next-s3-upload";
    import { useState } from "react";
    
    export default function UploadPage() {
      let { uploadToS3, files } = useS3Upload();
    
      let handleFileChange = async event => {
        let file = event.target.files[0];
        await uploadToS3(file);
      };
    
      return (
        <div>
          <input onChange={handleFileChange} type="file" />
    
          <div className="pt-8">
            {files.map((file, index) => (
              <div key={index}>
                File #{index} progress: {file.progress}%
              </div>
            ))}
          </div>
        </div>
      );
    }
  5. Configure environment variables for testing

    master

    Before running tests, you must configure an S3 bucket and create a .env.local file in packages/docs-site/ with the required environment variables. It is recommended to use a dedicated S3 bucket for testing as the suite performs multiple uploads.

    # packages/docs-site/.env.local
    
    S3_UPLOAD_KEY=XXXXX
    S3_UPLOAD_SECRET=XXXXX
    S3_UPLOAD_BUCKET=XXXXX
    S3_UPLOAD_REGION=XXXXX
  6. Customize S3 upload keys

    master

    By default, the addon generates a unique key for every upload. To customize the S3 object key (the file path), use APIRoute.configure to provide a key function in your API route. The key function receives the request object (req) and the original filename. It can be synchronous or asynchronous (returning a Promise).

    // pages/api/s3-upload.js
    import { APIRoute } from "next-s3-upload";
    
    export default APIRoute.configure({
      key(req, filename) {
        return `my/uploads/path/${filename}`;
      }
    });
  7. Run the Cypress test suite

    master

    The test suite uses Cypress and is located in packages/docs-site/cypress. To run the tests, you must have both the development build server (yarn dev) and the documentation site (yarn docs) running in separate terminals.

    # Terminal 1: Start build server
    yarn dev
    
    # Terminal 2: Start docs site
    yarn docs
    
    # Terminal 3: Run tests
    yarn workspace docs-site cypress open