The best way to Upload Images to AWS S3 from Your Next.js App: A Step-by-Step Guide(2024)

Views: 178Published: 7/21/2024
The best way to Upload Images to AWS S3 from Your Next.js App: A Step-by-Step Guide(2024)

Mastering Image Uploads in Next.js: A Developer's Guide


Ready to supercharge your Next.js app with seamless image uploads? Let's dive in!


What You'll Learn:


  1. Set up AWS credentials securely
  2. Create a function for S3 uploads
  3. Build an API route for blog post creation
  4. Process images for web optimization
  5. Implement server-side handling for speed and security

By the end of this guide, you'll have a robust image upload system that'll make your Next.js app shine. Ready to level up your development skills? Let's go!

Hey there, fellow devs! Today we're diving into some cool stuff with React, Next.js, and AWS. Before we jump in, let's ensure you've covered the basics.

Prerequisites:



Follow the below steps in order



Step 1: Where to handle the image upload


Next.js is pretty awesome for SEO and user experience. Why? Because it lets us do a ton of stuff on the server side instead of making the client do all the heavy lifting. This means better optimization and performance, and it makes Google Baba happy. So we're gonna stick to these best practices and handle our image uploads server-side.


Now, you've got two ways to go about this:

  1. 1. The classic API route system: It's like the old reliable of Next.js. Been around for a while, and gets the job done.

  2. 2. The new kid on the block - server actions: This is the hot new way of doing backend stuff in Next.js. It's more modern and streamlined.

    Both ways will get you to the same place - uploading images from the server side. But using server actions is like driving a fancy new car instead of your trusty old pickup. It'll feel smoother and more integrated with the rest of your Next.js code.

    The big picture here is that by handling image uploads on the server, we're keeping our app snappy and search engine-friendly. It's all about giving users a smooth experience while also playing nice with Google and other search engines.

    So, which route do you wanna take? The classic API or the shiny new server actions? Either way, we're keeping things server-side and optimized.


Step 2: Libraries required


Install below packages:

First up, we've got to install some stuff. Don't worry, it's just one package, but it's a biggie. We're gonna use the AWS SDK for S3. This is what's gonna let us talk to our S3 bucket and do all that cool image uploading stuff.

So, crack open your terminal and run this command:

npm install @aws-sdk/client-s3


2. So, here's the deal. We need a way to safely handle our AWS credentials, right? We don't want to just hard-code our secret keys into our app - that's like leaving your house key under the doormat. Not cool.

That's where this next package comes in. Run this in your terminal:

npm install @aws-sdk/credential-providers


This package is pretty slick. It gives us this nifty function called fromEnv. What does it do? Well, it lets us grab all our secret AWS stuff straight from our .env file. It's like a secret agent for your credentials.


Next up, we'll start putting this package to work. But for now, pat yourself on the back. You've just taken the first step towards some seriously cool image handling in your Next.js app.


Step 3: Setting up those AWS credentials


You're gonna need to grab some info from your AWS account and stick it in your .env file. This is like giving your app a special pass to talk to your S3 bucket.

Here's what you need to put in your .env file:

  1. 1. AWS_ACCESS_KEY_ID: This is like your username for AWS. It's a long string of letters and numbers.

  2. 2. AWS_SECRET_ACCESS_KEY: Think of this as your password. It's another long string but keep this one extra secret.

  3. 3. AWS_REGION: This is where your S3 bucket lives. Something like "us-east-1" or "eu-west-2".

  4. 4. AWS_BUCKET_NAME: This is just the name you gave your S3 bucket.

Your .env file should end up looking something like this:

AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_REGION=us-west-2
AWS_BUCKET_NAME=my-awesome-bucket


Remember, this .env file is your secret sauce. Don't share it, don't commit it to your repo, and definitely don't post it on Twitter. Treat it like your bank PIN.
Once you've got your .env file set up, you're ready to start talking to S3. We're getting close to the fun part now!


Step 4: Route where we get images from the client side

So, I consider you have your front end sorted out. When a user hits that "Upload Image" button, it fires off a POST or PUT request to your backend. Nice.

Now, let's focus on what happens when that image hits your server. We are going to create this awesome function called uploadToS3 in a new file. Let's call it s3Upload.ts. You can stick this file wherever makes sense in your project structure - maybe in a lib or utils folder. I have added it to the helpers folder.


This uploadToS3 function is the secret sauce. It's what connects us to our S3 bucket and does the heavy lifting of actually uploading the image. Here's what it's doing:

  1. 1. We're importing the stuff we need from AWS SDK. The PutObjectCommand is what we use to upload files, and S3Client is our main interface to S3.

  2. 2. We're setting up our S3 client with the region from our .env file and using that fromEnv function we talked about earlier to grab our credentials.

  3. 3. The uploadToS3 function takes three parameters: the file as a buffer, the filename, and the content type.

  4. 4. Inside the function, we're creating a PutObjectCommand. This is like giving S3 instructions: "Here's a file, here's where I want you to put it, and here's what kind of file it is."

  5. 5. We send that command to S3 using our client.

  6. 6. If all goes well, we construct and return the URL where the image can be accessed on S3.

  7. 7. If something goes wrong, we log the error and throw a new one to handle in our route.

This function is doing a lot of work, but it's all neatly packaged up for us to use.

Now, in your actual route handler (which we haven't written yet), you'll use this function like this:

  1. 1. Get the image from the request

  2. 2. Convert it to a buffer

  3. 3. Generate a unique filename

  4. 4. Call uploadToS3 with these details

  5. 5. Send back the URL to the client

Remember, this is all happening on the server side, keeping our app snappy and secure.


Below is the code you can copy & paste:

import {
  PutObjectCommand,
  S3Client,
} from "@aws-sdk/client-s3";
import { fromEnv } from "@aws-sdk/credential-providers";

const s3Client = new S3Client({
  region: process.env.AWS_REGION!,
  credentials: fromEnv(),
});

export async function uploadToS3(
  file: Buffer,
  fileName: string,
  contentType: string
): Promise<string> {
  try {
    const command = new PutObjectCommand({
      Bucket: process.env.AWS_BUCKET_NAME!,
      Key: fileName,
      Body: file,
      ContentType: contentType,
    });

    await s3Client.send(command);

    const s3Url = `https://${process.env.AWS_BUCKET_NAME!}.s3.${
      process.env.AWS_REGION
    }.amazonaws.com/${fileName}`;
    return s3Url;
  } catch (error: any) {
    console.error("Error uploading file to S3:", error);
    throw new Error("Failed to upload file to S3");
  }
}



Next up, we'll write the actual route handler that uses this uploadToS3 function. But for now, you've got the engine of your image upload system all ready to go. Pretty cool, right?



Step 5: setting up the image in the API route

This code is a great example of how to handle image uploads in a Next.js API route.

Here's the key part for image handling:

import { uploadToS3 } from "@/helpers/s3Upload";
import Sharp from "sharp";
//rest imports

//rest of the code

// Convert and upload header image to WebP
let headerImageUrl = "";
if (image) {
  try {
    const arrayBuffer = await image.arrayBuffer();
    if (arrayBuffer.byteLength === 0) {
      throw new Error("Empty array buffer");
    }
    const buffer = Buffer.from(arrayBuffer);
    const webpBuffer = await Sharp(buffer).webp().toBuffer();
    const fileName = `header_${Date.now()}.webp`;
    headerImageUrl = await uploadToS3(webpBuffer, fileName, "image/webp");
  } catch (error) {
    console.error("Error processing header image:", error);
    return NextResponse.json(
      { message: "Failed to process header image", success: false },
      { status: 500 }
    );
  }
}


This code is doing some pretty cool stuff:

  1. 1. It checks if an image was uploaded.

  2. 2. If there is an image, it converts it to an array buffer.

  3. 3. It uses the Sharp library to convert the image to WebP format, which is great for web performance.

  4. 4. It generates a unique filename using the current timestamp.

  5. 5. Finally, it calls our uploadToS3 function to actually upload the image to S3.


So, the returned URL we have got from uploadToS3 is now available to headerImageUrl which we can add to our database key while adding or updating.


This setup gives you a robust way to handle image uploads as part of your image upload process. It's efficient, it's using modern image formats, and it's integrated well with your S3 storage.


Now, let's wrap this whole thing up:

Conclusion:

And there you have it, folks! We've just built a pretty sweet image upload system for our Next.js app. Let's recap what we've done:

  1. 1. We set up our AWS credentials safely.

  2. 2. We created a handy function to upload files to S3.

  3. 3. We built an API route to handle image uploads.

  4. 4. We're processing images to make them web-friendly before storage.

  5. 5. All of this is happening server-side, keeping our app snappy and secure.

This setup isn't just cool - it's practical. It'll make your web app load faster, your storage more efficient, and your users happier. Plus, you're now handling images like a pro, converting them to WebP and storing them in the cloud.

Remember, good image handling is crucial for a smooth user experience and SEO. With this system, you're nailing both.

So go ahead, give yourself a pat on the back. You've just leveled up your Next.js skills and created a robust foundation for your web app. Happy coding, and may your uploads be ever swift and your images ever crisp!

🏆🏆 You are the Champ! now 🏆🏆



Additional Information:

For the comprehensive guide on how AWS S3 works you can read here. Click here to read