How to Upload Files to AWS S3 From NextJS App | by Szymon Kolber | Apr, 2022

Without the struggle with CORS policy.

Requests trying to reach the different origin

NextJS is a frontend framework, and since the frontend doesn’t have an access to the different origins due to the CORS policy, it’s tedious to implement it if you’re doing it in the wrong way. Of course that you can alter going out requests in the next.config.js file with redirection from an API route, but then using NextJS serverless API which is super handy, lose its benefits. In this “fast, to the point” article we’re gonna go over the steps needed in order to make it work.

Btw if you prefer to work with ready code, you can find such here:

If you don’t know what AWS S3 is, S3 stands for Simple Storage Service and it’s exactly that. It allows you to store all of the different files online on Amazon servers, and retrieve them fast and safely. An additional bonus is the “pay as you scale” business model, which let you try the service out, even use it in production for free if you’re needs aren’t that big. With that said, let’s now focus on what we have to do in order to use it in our web app.

1. Create an AWS account

You can sign in to the console there. The difference between a root user and an IAM user is, that a root user’s credentials are the credentials through which you’ve registered, providing your card and billing details. IAM user accounts are the ones, which you create for individual AWS services. Summing it up, you want to create a root user there.

Amazon sign in to the console page

2. Navigate to the S3/IAM service

AWS screen after logging in

If it’s your first time using AWS, don’t worry, it’s intuitive. Basically, you have an access to all of the services from one account, and you search for them either from the recently visited services section or the search bar. In the case of this tutorial, we’ll need just two services — S3 which will provide us with storage capabilities, and IAM where we’ll create access policies.

1. Creating a bucket

The first thing which we’ll gonna configure is S3. As you can see in the below image S3 works on “Buckets” philosophy. You create a bucket in which you’ll store your files.

Bucket page

While creating a bucket you’d probably like to leave almost everything as it is, with an exception to the “block all public access” option. Since we want to allow a public upload from our users, we’ll live it empty.

Leaving the “Block all public access” option empty

2. Bucket properties configuration

Bucket Policy — are responsible for managing access. For the sake of simplicity, we’re gonna set it to the public so we can access the resource afterward without any unnecessary authentication. The configuration is pretty standard. Just remember to insert your bucket name in the place of YOUR_BUCKET_NAME_HERE if you’re copy-pasting it (of course you are, we’re all programmers).

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicListGet",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:List*",
"s3:Get*"
],
"Resource": [
"arn:aws:s3:::YOUR_BUCKET_NAME_HERE",
"arn:aws:s3:::YOUR_BUCKET_NAME_HERE/*"
]
}
]
}

CORS — Cors properties also can be set from within the permissions tab. Feel free to copy-paste my configuration, which as you can see is nothing crazy. We basically allow all of the origins to access our bucket.

[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT",
"POST",
"GET"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"ETag"
]
}
]

IAM aka API Key

Since we’re gonna connect with Amazon we need some sort of authentication. We can do it from the IAM section. As you can see I already have one user group created

User groups page

Click create group, and you’ll be able to choose appropriate rights. Simply go with AmazonS3FullAccess.

Setting group permissions

Afterward, you should see a group that you’ve just created in your panel.

Created group

Then we want to create a User to which we’ll assign an access group created a second ago.

Creating an IAM user

Choose programmatic access since we want to elevate AWS SDK using an API, and for this purpose, we’ll need API credentials. After successful user creation, you’ll be able to fetch its Access key ID and secret access key. You want to grab those, and we will make use of them in the next section related to Next JS.

User credentials

Phew, we have the least intersting work done (I’m sorry AWS admins, it’s just my personal opinion). Now we can answer the question about how we can upload files using a frontend framework.

First and foremost, it’s important that it will not all be frontend. Since we can’t really have environment variables on the frontend (because it’s all compiled into Javascript code, and at the end of the day all will be visible in the browser), we will elevate NextJS API routes. That’s basically a serverless solution that is simple and intuitive to use.

So how will we approach this problem? We will create an API route, which will create signedUrl for us, to which we then gonna make a PUT request passing the file; we want to upload as a body. If it sounds complicated just go through the code, it will have much more sense in a minute.

1. Installing NextJS along with Tailwind CSS and Typescript

I don’t know about you, but my preferred way of working with NextJS is to do it with Typescript and Tailwind CSS. Typescript gives me type checks, and tailwind allows me to write CSS super-fast, almost like on the steroids. To save yourself a hassle in setting it up, here is a template with preconfigured Typescript and Tailwind which you can use:

2. Install necessary libraries

For this to work we just need two libraries:

  • axios: which allow us to make HTTP requests,
  • aws-sdk: which allow us to make use of AWS services
Installation of needed libraries with yarn

3. Create file input

The following code creates just a simple input of type file, which allow us to fetch a file we’ve inputted in.

Code for creating simple HTML input

In case you’re doing it for the first time, this is how the file information is stored inside a javascript.

Input type file output information

Let’s just store it in useState.

File useState hook

4. Store your API keys from an AWS in .env.local file

Remember as I told you that there’s no really something like safe stored environmental variables in frontend? I’ve meant that. But since Next JS API is serverless and it’s our backend we can safely make use of them here. Any environmental variables which are not prefixed with NEXT_PUBLIC_ won’t be exposed to the browser. In .env.local file create three variables ACCESS_KEY, SECRET_KEYand bucket name:

5. Set up an S3 instance and config properties

First things first. You have to import S3 and create a new instance of it. As you can see properties are pretty self-explanatory, you have to specify a region, pass an access key and secret key, and signature version which we’ll set to v4. In NextJS if you would like to specify any different than default body-parsing properties you can do it in the config variable which you have to export. We’re setting a maximum uploaded file size to 8mb.

Creating an S3 instance and exporting a config

6. Create an API route logic

First, we exclude any other HTTP method than POST, then we create file params needed for s3 to generate a signedUrl for us. As you can see there are some options needed. In the POST body, we send a name and the type of file, which we want to upload. We also set the “expires” time to 600 seconds, and ACL for the “public-read” which will make this asset publicly accessible.

API endpoint configuration

7. Uploading a File to AWS S3 bucket

Protip: if you’ve added your .env variables after starting up an app with yarn dev, remember to restart it, because env variables are fetched at the start of an application.

Uploading a file and using a previously created API endpoint

We first make use of the previously created uploadFile endpoint, to which we send the name and type of a picked file. Then we fetch the URL which will allow us to upload a file to the AWS. The URL looks like in the screenshot below. Afterward, we send a PUT request with the file to the received URL.

Example of signed URL which we received from the API endpoint

In the URL the part till “.com/” is your bucket URL. You can copy it and store it somewhere if you want to access it later.

8. See the uploaded file in your bucket

Now you should see your freshly added file in the bucket. We’re done here.

Successfully uploaded file in the bucket

If you would like to display an image in the HTML you can do it like that

Displaying saved image

In this article, you’ve learned how to create an AWS account, and how to create an S3 bucket along with IAM users. Now you’re also capable of NextJS app creation which will provide the functionality of uploading files to your bucket, and displaying results.

If you want to grab a code, it’s available here:

Leave a Comment