Uploading Files to Amazon S3 in a Next.js Application Using AWS SDK v3

Sh Raj - Jun 26 - - Dev Community

Uploading Files to Amazon S3 in a Next.js Application Using AWS SDK v3

In this tutorial, we will walk through how to upload files to Amazon S3 in a Next.js application using the AWS SDK for JavaScript (v3). We will ensure that the files are served securely over HTTPS using the appropriate URL format.

Prerequisites

  • Basic knowledge of Next.js
  • An AWS account
  • Node.js installed on your machine

Step 1: Set Up Your S3 Bucket

Create an S3 Bucket

  1. Go to the AWS Management Console.
  2. Navigate to the S3 service and create a new bucket.
  3. Choose a unique name and a region closest to your users.
  4. Set up the bucket to allow public read access for simplicity (you can refine the permissions later).

Set Bucket Policy and CORS

Bucket Policy

Add the following bucket policy to allow public read access:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-bucket-name/uploads/*"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

CORS Configuration

Configure your bucket with the following CORS rules:

<CORSConfiguration>
  <CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
  </CORSRule>
</CORSConfiguration>
Enter fullscreen mode Exit fullscreen mode

Step 2: Set Up AWS SDK v3

Install AWS SDK v3

In your Next.js project, install the required AWS SDK packages:

npm install @aws-sdk/client-s3 @aws-sdk/lib-storage
Enter fullscreen mode Exit fullscreen mode

Step 3: Create an API Route for File Upload

Create an API route in your Next.js application to handle file uploads to S3.

Create /src/app/api/upload/route.js

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';

const s3Client = new S3Client({
  region: process.env.AWS_REGION,
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  },
});

export async function POST(req) {
  try {
    const { file } = await req.json();
    const base64Data = Buffer.from(file.replace(/^data:image\/\w+;base64,/, ""), 'base64');
    const type = file.split(';')[0].split('/')[1];

    const params = {
      Bucket: process.env.AWS_BUCKET_NAME,
      Key: `uploads/${Date.now().toString()}.${type}`,
      Body: base64Data,
      ContentEncoding: 'base64',
      ContentType: `image/${type}`,
    };

    const upload = new Upload({
      client: s3Client,
      params: params,
    });

    const data = await upload.done();

    // Generate the URL in the desired format
    const url = `https://s3.amazonaws.com/${params.Bucket}/${params.Key}`;

    return new Response(JSON.stringify({ url: url }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (error) {
    return new Response(JSON.stringify({ error: error.message }), {
      status: 500,
      headers: { 'Content-Type': 'application/json' },
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Create a File Upload Component

Create a file upload component to allow users to upload files from the client-side.

Create /src/components/FileUpload.js

'use client';

import { useState } from 'react';

const FileUpload = () => {
  const [file, setFile] = useState(null);
  const [message, setMessage] = useState('');

  const handleChange = (event) => {
    setFile(event.target.files[0]);
  };

  const handleSubmit = async (event) => {
    event.preventDefault();

    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onloadend = async () => {
      const base64data = reader.result;
      const response = await fetch('/api/upload', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ file: base64data }),
      });

      if (response.ok) {
        const data = await response.json();
        setMessage(`File uploaded successfully! File URL: ${data.url}`);
      } else {
        setMessage('File upload failed.');
      }
    };
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="file" onChange={handleChange} />
      <button type="submit">Upload</button>
      {message && <p>{message}</p>}
    </form>
  );
};

export default FileUpload;
Enter fullscreen mode Exit fullscreen mode

Step 5: Use the Component in Your Page

Include the FileUpload component in one of your Next.js pages.

Create /src/app/page.js

import FileUpload from '../components/FileUpload';

export default function Home() {
  return (
    <div>
      <h1>Upload a File to S3</h1>
      <FileUpload />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Configure Environment Variables

Ensure you have the necessary environment variables set up in your Next.js project. Create a .env.local file in the root of your project if it doesn't exist:

Create .env.local

AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_REGION=your-region
AWS_BUCKET_NAME=your-bucket-name
Enter fullscreen mode Exit fullscreen mode

Replace your-access-key-id, your-secret-access-key, your-region, and your-bucket-name with the actual values from your AWS account.

Step 7: Restart Your Development Server

Make sure to restart your Next.js development server to apply the new environment variables.

Conclusion

By following these steps, you should be able to upload files from your Next.js application to an S3 bucket using the AWS SDK for JavaScript (v3). The files will be served securely via HTTPS using the correct URL format. Happy coding!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .