 Hey welcome everybody, in this video I will guide you through the process of creating an AWS S3 bucket and applying public permissions so that the files are available to anybody on the internet. In the second half of the video, we will create a file upload form using Next.js and the official AWS S3 client SDK. This time as requested, we will use server actions to do the file uploads. Hey welcome everybody and let's get started. I've already logged into my AWS account and I'm currently here on the dashboard. Now let's create all S3 buckets. So search S3, find the service here, click on it. From here, let's click create bucket. Choose your region for me. This is going to be Europe London. The bucket name I'm going to put as my next js-website and leave everything else as it is. Then scroll down for the object ownership. I'm going to leave it as the recommended here, ACS disabled. Let's scroll down a little bit more. We have public access settings for this bucket. So as of now, I'm going to leave this the way it is. So this is going to be ticked. But later on, I'm going to show you how we can change this so all files are publicly available. And if you scroll down a little bit more from here, if you wish to, you can enable bucket versioning. I'm going to disable mine. If you wish, you can add some tag and put the default encryption. I'm going to leave mine as server site encryption with Amazon S3 managed keys. Bucket key is enabled and that's pretty much it. Let's click create bucket. Okay, now that our bucket is created, let's select it. And from here, let's upload a file. So I'm going to click upload, add files. I'm going to select an image that I downloaded from a splash and then scroll down and upload. And now we have the images here at the bottom. If I click on the name of the image here, this should lead you to the properties of this specific image. And from here, you can see the type, the size, when it was last modified. And here on the right side, we have the actual URL. If I was to click on the URL right now and open this in another browser, basically here, you will see that we are getting access denied. So if you wish to, you can make this file publicly available. And if I go back, what we need to do is go back to a bucket. So I'm going to click on destination here and then we're here under our bucket. As you can see my next JS website and we need to go to permissions from here. We need to go to your block public access and click on edit and block all public access. So basically everything here isn't ticked and we need to save changes. Confirm and then confirm. OK, now that our public access is enabled, we still won't be able to see the image just yet. If I refresh on the image, you'll see still access denied. And this is because we need to apply a bucket policy. So again, under permissions here under bucket permissions, scroll down and we have bucket policy. From here, if you click edit, you'll be able to see that they have a policy generator which you can use. It's quite complex, but if you know what you're after, you should be able to use this and make it work. Alternatively, obviously you can use AI to generate one for you and you can test it. Or you can go here under policy examples. And if you click on this on another tab here, you will see that if you scroll down a little bit, you will see that they have a lot of different policies here. So you can scroll down and find maybe you can find one that works for you. As you can see, you can allow access to only your organization. You can manage access based on specific IP, which can be quite useful and so on. So I've already created a policy, which I'm going to have in the description below and I'm going to close this. So let's go back to the policy here. So I'm going to copy my policy and paste it here. And essentially, this policy is going to allow the public read access. And one thing that you need to change from here is the resource. So we need to select which resource we want to use. And in order to find your resource is basically here. So copy this, don't replace the star here just before the slash, remove everything and paste. And that's it. So now if I save this policy, save changes here at the bottom. OK, successfully edited bucket policy. And now if I go back to the image and refresh. You should be able to see that the image is now loaded. And this is actually a fairly large image. And that's why I get a lot of scroll. Let's close this. And now basically, if you go to objects, you can literally select on an object. You'll be able to see that this is going to be the prefix of your bucket. And then you have the actual file name here at the end, which means that you can use this to save to your database and then maybe display images on your website if you wish to. OK, that's all cool. Now, in order to be able to upload images from our application, we need to do one more thing. We need to create a user and give that user access to a bucket. And that user is going to give us the API keys. But the first thing that we can do from here is make a note of our AWS region. So what I've done is I've already created a notepad file, which I'm going to zoom in here. I can copy this as well in the description below. But essentially, we're going to need a region access key, secret access key and a bucket name for the region. I can just copy it from here, EU dash West dash two, and I'm going to paste in here. And for the bucket name, we already know it from here. So my next JS website, I'm going to copy it here. And now we just need the access key and the secret key. So I'm going to move this and let's go back to our dashboard here. And from here, we need to search for identity and access manager for short. I am I am. And here it is. Select this. And now we can create a new user from here. You can either scroll down and select here. Users or here on the left side, you have also users under access management. So I'm going to click on users. And essentially, we need to create a new user from here. So I'm going to click create user. And let's give this user a name ready next year's server actions. And then let's click next. From here, I've already created a group which gives which I can select. But because you won't have this, let's create a new one and I'm going to search for this as well. So let's create a new group by clicking create group. And from here, we need to give it a name. Maybe I can do next JS tutorial and then Amazon S3 full access. And this is what we need to search for. So permission policies, we need to search for this permission policy, Amazon S3 full access and selected. So we're basically allowing this user to manage all S3 bucket. Create this user group. And of course, as you can see, I've applied this previous one to two users and you can do the same thing for the one that you just created. So from here, make sure that you select this. Don't forget it because you do need to add your user to this user group. I'm selecting it now and let's click next. Okay. Everything is looking good here. All I need to do is create the user and we should be good to go. Now let's click on or newly created user from here and here on the top right corner, you should have access key one. Click on create access key. From here, I don't think that matters which one you select abuse the command line interface before, and I've also used other. So I'm going to select it at this time and then click next. I'm going to skip the tag value here. I don't need this and let's click create access key. Okay. And now we have access key from here. Let's copy it and let's paste it into a notepad. So this is going to be my access key here and let's copy the secret access key. So I'm going to show and copy and let's paste it inside here. Whoops. Okay. That's all looking good. This file somewhere for now, just so you don't lose it. And that's it. I'm going to minimize this and now just click done. Okay. We are pretty much done with this. Let's just go back to a bucket. Let's select our bucket here and now we can start working on our next project. Let's start by creating a new project. I'm going to blast through this super quickly. So let's just right click open in terminal. I'm going to paste the command, which is npx create dash next dash up at latest presenter. I'm going to give my project a name. Yes, S3, server actions, my center, tab script now, ESLint now, terwin CSS now, source directory yes, uprouter yes, import alias no and that's it. I'm going to copy the name of the project and CD to it. So CD and paste the project name here and we are now inside the project folder and I'm going to open this with VGTD code. Here we have our newly created project. I've zoomed in quite a bit just so I can fit stuff on the screen really. And now I'm just going to run the project. So I'm going to do npm run def and it looks like the port of 3000 is already been taken, but I don't restart my PC. So 3001 is going to do the job. I'm going to copy this and then let's open it in the browser and our project is working. So I'm going to put the VGTD code here on the left side and the browser on the right side so we can see what's happening as we go along. All right, before we get one thing that I wanted to talk about is the approach that I'm going to be using today. If I go to server actions and mutations here and if you scroll down a little bit, you'll be able to see that the two main methods of doing this. You can either use server components and write their inline like they have an example here. You just have to do your action here and use server and you'll probably end up, if you have a big form, you'll probably end up splitting your form into multiple files. If you have a small form, you can even leave it in here. And the other way is by using the client component. And here you have to separate your files into three. So you can separate your file into actions, button and then form. I actually really like this approach now. So I'm going to use this second approach. But either way, if you'll follow along, you'll be able to potentially convert it into this method if you have a smaller form. And if that's something you want to do, close this and let's go to our project. The first thing I'm going to do is remove the style. So I'm going to go to source and then global CSS. Let's remove everything and save. This will break the front page, but it doesn't really matter. I'm just going to create a new page and create the form there from here. I'm going to copy and paste a little bit of CSS and it's super basic. I'll show you what it is. So I'm going to copy and paste it. If I zoom out a little bit, it just makes the form a little bit better. Basically, if you wish to, you can copy the CSS from the main repository. But essentially, I'm just creating a wrapper so we can give the form a max width. Some of the inputs have a little bit of spacing at the bottom here. We have a little bit of styles for the input and button. And then we have different states for the messages. So we have state message, which gives it a padding, centers the text in the middle. Then we have two states of state message success, which is green state message error, which is red. And then we have the submit button, which has just changed pretty much to a green color. And I've also used the native CSS nesting here, but you don't need to do that. So I'm sure that you'll come up with better styles. Save this, zoom in and close it. All right, let's open the explorer here. And the first thing that we need to do is to add all environment variables that we recorded earlier in the first part of the tutorial. So here they are. So I'm going to copy this and I'm going to create a new file here in the main directory called dot EMV dot local and that should do the job. And inside here is where I'm going to paste the environment variables. So paste them and we have the region, the access key, the secret key and the bucket name. That's it. Save this, close it. Let's go back to the explorer and then inside the app order here, let's create a new page. So you can call this page, whatever you like, it can be dashboard, upload, whatever. For me, I'm just going to stick to upload and press enter in order to create a basic page. To create a file called page dot JS and inside this page, we need to do the very standard export default function and call a page like so. And then we just need to return something. So in this case, I'm just going to open and close fragment here and then this is going to be an H1. Let me just change my spaces to two. I don't know why that keeps changing. Okay, that's much better. And now here I'm just going to say an H1, upload files to S3 bucket. And that's it. Our page is done. Let's visit in the browser by doing such upload and press enter. And as you can see, we have upload files to S3 bucket here. This is the name of the page. All right. So we need to split our form into multiple files and our form is basically going to be inserted in here. If I go to the explorer and then inside uploads, I'm actually going to group the actions. And this is really up to you how you organize your files. So because this upload action is only going to be used in this upload page, I'm going to group them by doing parentheses and then form like so. So we're just going to group the form, all the form files inside here. And as I said, feel free to organize your files however you like. Now from here, let's create our form. I'm going to create a new file and let's just call it form.js. Let's focus on the form and let's create something very basic to style it. I'm going to do export function and this is going to be called upload form like so. And then inside here, we can do return and then we can just return a form. I'm going to wrap this into a div with the class name of form wrapper. As this is what I added to my CSS and let's close the div here. Let's add our form. So form, we need to give it a action. So form doesn't break. I'm going to add the action in a second. Let me fix the spaces one more time. So I'm going to remove this move that. Okay. Inside of form, we need to create all input, which is going to take the file. So input type of file, and then you can give it an ID or file, if you wish, a name or file and then what do you want to accept? In this case, I'm just going to be using images, but you can use whatever you like. So I'm going to say I want to accept only images of all formats. Of course, you can specify them in here and I'm just going to close this. This is a safe closing tag. So that should be good to go. And the last thing that we need here is to create or button for the button. Let's create something basic to start with. So I'm going to create a button and close it. So this button is going to have the type of submit and I'm just going to write upload a file for now and save it. All right. Now that we have a very basic form, let's insert this into our page here. So at the top, because we're using the client method of server actions, we're going to have to add use client here at the top. Otherwise this form work and now we need to import our form. So let's do import curly brackets. We can do upload form, press enter. And we need to do add slash and then up slash upload slash form and then slash form. And now we should be able to insert a form into this file by copying the name from here and replacing it here. So open upload form and close it. Save it. And as you can see, we now have our form in here. All right. And Ossises is actually working, but I didn't add a class name to our button here. So if we add the class name of submit button, it should make it look a little bit more presentable and that's it. There is not much styling on this form. All right. We almost done with the skeleton of our form, but the last thing that we need to do is the action and then we'll build on every single file. If I go back to the form here, we need to create one more file and this is going to be called actions.js. And to start with, this needs to be use server. And the first thing that we need to import is revalidate path. So let's do import in curly brackets, revalidate path from next cache. So essentially when we submit a form, we want to clear the cache and revalidate the path. Basically it can be working kind of like a redirect to the same page without a refresh. It's pretty cool. And now we need to create our form. So let's do export async function and or function is going to be called upload file. And this function is going to have a previous state and form data. So if we go back to the documentation super quickly, basically we're going to be using use form state, which is a react hook that allows you to update state based on the result of a form action. And here we have bypassing the action from use form state. The actions function signature changes to receive a new previous state or initial state parameter as its first argument. It's a little bit confusing, but you'll see how this works in a second. Let's minimize this. And from here, let's open and close curly brackets, wrap everything into a try cache statement because this is going to be quite useful later. And from here, we can use the form data to grab the field and then use the file to upload to DS3 bucket. So in this case, if we do console.log and then form data in a second, you'll see how this works. And also we can use the revalidate path here. So when we submit you, we revalidate the same path like so, and we can return a message. So return. And then in this case, we're going to have a status message of success and we're going to have a message, which is going to be hard coded in this case. So has been uploaded like so. And I'm going to copy this and paste it for the error here, and I'm going to say error. And then the message is going to be failed to upload file. All right, let's have a look at how this is going to work now. Now that we have the actions here, go to form super quickly, and we need to insert this file at the top. So from here, we're going to do import, upload file, and then this is going to be close, but this is going to be at slash app slash upload slash form and then slash actions. And that's it. Now we also need to import the use form state, which I was talking about earlier. So I'm going to do this at the top here, import, use form state. And then this is coming from react DOM like so. And now you see how everything is going to start working together. So first of all, on the form, we want to set an initial state. So to do this, I'm going to do a const. Let's call a initial state, and this is going to be equals an object of message. And this message is going to be said to know as default. And now inside of form here, we can do const state form action. And then this is going to be using the use form state. And then we're going to be using the action here, which is the upload file. And then then we're going to set the initial state. It's a little bit confusing, but you'll see how it works in a second. And now essentially for form action, we can use this. So instead of double quotes, we just put curly brackets and then put form action. So as default, we have the form and the default message is no. I'm going to press upload files. You can see nothing is happening at the moment. And one thing that we can do straight away is from actions. If you remember, we put status of success and status of error, but you can also grab the error from the S3 buckets, which we'll look into later on. But inside form here, we can create some sort of like, for example, we can use state, question mark dot status, and basically we're checking if this is not empty. We want to display some. Let's display a div in this case. And I've already prepared a class name for this, only in the tutorial. Where is it? So global CSS, I've prepared a class name of state message, and then we can just put success or depending on what we get. So from here, in curly brackets, single slander quotes, and I'm going to put state message as or CSS. Depending on the status, we can put it in here with template liter, so I'm going to grab this state, question mark status dot status. So depending whether this is success or error, it's going to change green or red. And then we can close this div. And inside the div, we can put the actual state message dot state, question mark dot message, which comes from here, so message file has been uploaded to fail to upload file and then just close and save. So now that I saved it, as you can see, file has been uploaded. Obviously, file has not been uploaded because we haven't done any of the S3 stuff yet. But if I refresh, you will see that the current state of this is set to no. So the message is no. But if I click on upload file, file has been uploaded. And if I go here to the action dot js, and if I make an error, I don't really know how to error this, but let's just put a very bad error like so and save it. So now if I upload file, you will see that this block has errored. And now we have failed to upload file here in red. And of course, you can start this however you like. Okay, we're getting close. So let's remove this and let's now focus on one problem that we're going to have with the button. The problem that we're going to have with the button is that when I click on file upload from here, we won't be able to actually change the state from it. So what I mean by this is that when I click on the button, you might want to change this so you can't double press it, and maybe you want to change the text inside here. And unfortunately, in order for this to work, we're going to have to move this button into another file, otherwise we won't work, which is a little bit weird, but it's not so bad. Cut this, save this form, and let's create a new file here. So inside form, let's create a new file, and I'm going to call it submit button dot js. And let's create it. And this is going to be use client and then we're going to import the use form status from and then this is going to be react dumb. And this is going to allow us to do a pending button. So export function, let's call it submit button. So it's prettier. And then from here, we can set a const of pending and then this is going to be equals use form status like so. Now we just need to return and we return the actual button like so. And in order to use the pending, there are two things that we can do. First of all, the most important thing here, let me format my document because again for spaces, format doc, okay, much better. So the first thing that we can do is you don't want to double press the actual button and in order to stop that, we can use the pending from here and put it inside area disabled. So area dash disabled, like so, and we can just set the status here in curly brackets of pending, which is awesome. So that should stop you from double clicking the button. And the other thing that we can do is changing the message here. Let's leave as it is and we'll change in a second. So let's import this into a form as well. So I'm going to go back to the form here and let's import the button. To import the button, it's going to be very much the same as this. I'm going to all chip down and I'm going to put here submit button and this needs to be changed to submit button, like so. And now we can grab the button here and insert it into our form, like so. The same reason we are getting an error, let's have a look at it. So submit button and I have a spelling mistake here. So use instead of use form, I've misspelled it here. So it's use form, like so status, okay, my fault. And let's paste it in here. Save it. And as you can see, we have our button. Now, if I press the button here, you'll see that nothing is happening. File has been uploaded. All good. But if you wanted to change this, we can also do that now. Okay. So there are two ways of doing this. And the first one would be to just put file upload. And then inside here, we can use the pending. So I'm going to do pending and then and and and then in double quotes, I can just do three dots. So now if I press the file upload, if I zoom in super quickly, and if I press it, you'll be able to see that we are adding the dots here. As you can see, it changes. And you can also do something like file, file upload ink dot dot dot. And that will work if I save it. And that would probably work in English, but in other languages that might not work. So what I'm going to do is let's remove this. And let's just do pending. If it's pending, then we want to set uploading dot dot dot. And then if it's not, we just say file upload. And that would be the same thing, basically. So now we have file upload. And if I click on it, you will see that it changes really quick. But later on, we'll change the internet connection and you'll see that changes. OK, your form is finally complete. And finally, we can start using the AWS SDK for JavaScript v3. So the first thing we need to do is install it. You can use NPM, Yarn or PNPM. And I'm going to copy this one here with NPM. Let's stop the process of our application. Let me see if I can. Here we go. NPM is to add AWS dash SDK slash client dash S3. Press Enter. Let's run our project NPM run dev. Press Enter. And we should be good to go. OK, let's go back to the project. And by the way, the documentation that I just showed you has a lot of examples. So if you wish to, you can pause the video and have a look into it. All right, in this case, we've pretty much done everything. And now we can focus on the action of our form so we can upload a file. Let me refresh it just so we can see that our application is working. Yep, everything is working fine. So let's close everything except the actions. Close, close, close. And this is where we're going to do all S3 bucket logic. From here, let's import all S3 clients. So import S3 client. And this is coming from AWS dash SDK slash client dash S3. We also need to import put object command, which is going to allow us to insert a file. So put object command like so. And that's it. Now we need to set up all credentials. So all credentials are going to be inside EMV.local in this case. And I'm going to copy all of them. And super quickly, I'm going to paste them and just remove everything else. We don't want them. That's it. Let's see if I can comment them super quickly. Yep. Okay, I can comment them. So we need to set up all credentials using the S3 client. Now to start with, I'm going to do const and you can name this whatever you like. Just don't name it the same as this or what I'm going to do is put small S and then free client. And then this is going to be equals new. Now we can use the S3 client from here to create a new object and set up the credentials. So the first thing that we're going to have is the region. And then we're going to have the EMV file from here. So process, now EMV and then the region that we have in all EMV comma. And then from here, we need credentials. And for the credentials, we're going to have an object which contains the access key ID. Like so. And the access key ID is this variable here. So process.emv.access, yep, that's it, comma. And then we need the last one, which is secret access key. And this is going to be the secret access key. So process.emv.next-years-secret-access-key, like so. That's all looking good. We definitely don't want those first three in here because we just need to add the bucket name in the next step. Before we do that, let's focus on the form. So when we submit the form, we can grab all of the data from the form data here. That's why I'm actually console logging in. And what I'm going to do now is I'm going to choose a file here and I'm going to submit this cat and let's click file upload. Let's go to the console super quickly and you will see that we're getting all these messages. So we're actually getting here at the bottom, as you can see, name, file, and then we have value or file, which we can access. So it's actually picked up the image and this name file comes from our form, which is here. So here it is. So this is where it comes from. And in fact, if we do another input, just so I can show you input, let's give it a type of text and let's give it an ID of, let's say username and then name of username just for the example. All right. If I save this, and if I was to submit read and file upload, if you go back to the console, you should be able to see that here at the bottom, now we have another input, which we can access here, which is the name of username and the value of rat which comes from the input. This was just an example. I'm going to remove it just so you can see the difference here. So I'm going to remove this and let's save this. Let's go back to the actions here and let's set up the rest. So I'm going to remove the console lock here and let's just make sure that we select the file so we can upload it. In this case, I'm going to do const file and this is going to be equals the form data and we're going to get the file. And now what we can do is do a quick check to see whether we have selected the file and we can upload it. And if we don't, maybe we can just display a message. So what I'm going to do here is I'm going to do if the probably other ways of doing this, but the solution I came out here is that we can grab the file and each file actually has a size. So I'm going to size. In fact, I can console lock this in second view and if the size is equals equals equals zero, then can return the status from here. So I'm going to do the error. Like so. I know it's hard coded, but status is going to be error. Message failed to upload file. Now we need to change this to please select a file and what I can show you here is that if we console lock the file, if I do console.log file super quickly and if I do, let's select one. Let's select the cut here and I will upload. Okay. If I go back here, you will see that when I console log the file, we have the file and this file has a size, image type, name and last modified. So we can definitely use this to advantage to check whether the file is zero and then we can also use the name to insert into database. If we have one, we don't in this case, or we can use this name to insert into S3 bucket. So pretty useful information here and I'm going to remove this, tidy things up. And now if we get a file, we also want to continue and we're going to do const buffer. This is for file and we're going to be using buffer.from and we're going to await file dot array buffer. And if we go super quickly to the developer dot Mozilla dot org, you will see that the array buffer object is used to represent a generic row binary data buffer. It's an array of bytes often referred to in other language as byte array. Let's close this. That's how we're going to be able to upload the file. And now we need to create or upload function. So I'm going to do await. And then this is going to be called upload file to S3 S3. And then we're going to grab the file from here, buffer. And then as I showed you earlier, when we console log the file, we can grab the name but then file dot name as well. So we can pass those two into the function that I'm going to create now. So let's create this function. I'm going to copy the name and we can create around here. So this needs to be an asynchronous function. And so a sync function and let's give it a name of upload file to S3. I'm going to make some space here just so we can see. We're going to grab the file and then we're going to grab the file name from here, file, file name that comes in this function. And then from here, from here, I'm going to do const and I'm going to create a variable called file, buffer. And this is going to be because the file, this can be quite useful. If you want to use a library like shout, for example, to crop your images or to optimize your images, that can be quite cool. And then from here, we're going to do const. And we need to set up the bucket parameters. So params equals. And then in an object, we're going to do bucket. And this is going to be the bucket name. So I'm going to grab a from or EMV file, remove this. So this is going to be process.emv.next, underscore AWS, underscore S3, underscore bucket name. Then we're going to have comma, we need the key and the key is essentially or file name. So inside here, we're going to grab the file name and I can put it in template rituals for now. I'm going to show you why in a second. So we're grabbing the file name, for example, cut.jpeg. And then the body is where we actually insert the file. So you can either use file from here, just but file, or you can use the file buffer and put it inside here like so. And that's going to upload the image. And then the last thing that we need to do is the content type. For me, I'm just going to be using images in this case. So I'm going to do image dash JPEG and then make sure that you see the content types available from the official documentation should be easy to find. And the last thing that we need to do is use this, put object command in order to insert the actual image or file. So in this case, this is going to be inside the same function here. And we're going to do const command equals new, put object command. And then we pass the parameters inside here. So you can pass it inside here, or you can copy the whole object and put it inside here, whatever you prefer. This seems a little bit cleaner. And then here, I'm going to do a try catching this case. Just in case the file doesn't get uploaded. So I'm going to do const response equals await. And then we're going to wait for the S3 from here, S3 client, with the small letter dot send. So we're sending and we're sending this command with all the parameters. And from here, you can console log your response if you wish to. And just pretend the file name, so return, file, name like so. And then for the error, you can just do throw an error or whatever you wish. And that's it. So now, after all this, let's right click and format this document. It's all looking good. Hopefully we won't have any errors. But now if I open my bucket here super quickly, let's put it to the left. Let's put on the left side super quickly. And as you can see, we only have the first file that I uploaded manually. But now if I click on choose file, and let's select the cut super quickly and press file upload. Uploading and it finished. File has been uploaded. If I refresh, hopefully we should see the cut. And here it is. So we have the cut inside here. We have the kilobytes. So if I click on them, we have everything about the image here. And if I click on the object, you will see that we're getting the kitty here. So let's do one more. And in this case, I'm going to open the inspector tool. And if I can undock this, I'm going to undock this super quickly. And what I want to do is mimic a slow connection. So let me remove the mobile. And if you go to network here, and if you can see, here we go. If you go to network here, you can do a slow internet connection. So no fraudulent. I can do it as potentially slow 3G. And maybe I can choose one of the large images. Let's see what happens now. I'm going to refresh the browser. And now, okay, everything is loading. It's taking a while. All right. This is slower than I expected. All right. This was a little bit slower than I expected. So now that our page has finished loading, let's select a bigger file like this one here. And let's do file upload. I'm going to click there. As you can see, we're getting uploading. Of course, you can change the color of this. You can change, you can add animation here or whatever, but we have uploading. And this, I think it's a fairly large image. So I'm assuming that this is going to take a while and I'll come back to it once it's done. All right. This is taking generally too long. So what I'm going to do is let's switch to, let's switch to 3G. All right. No fraudulent now. Let's refresh. And now let's set this to fast 3G. And now let's upload the cat one more time. I'm going to select it because those two files are too big. I'm going to select the cat and then file upload. As you can see, these changes to uploading. And as you can see, yep, you probably saw the request here. And then we have our has been uploaded. Yeah. And that's how it works. And the last thing I'm going to remove the fraudulent. Let's close this. So if we go back to here, as you can see, I uploaded the cat a couple of times now, but we only got it once. And the reason for this is because every time I upload a file with exactly the same name, it just replaces it instead of uploading a new file. And the reason for this is because of the name. So what you can do here in the params file name is you can set up unique name. You can use a third party library or you can do something like, I don't know, something like date now. Let's do in dollar sign curly bracket date now and see whether we can upload another cat. So I'm selecting the cat here, file upload, it's uploaded. And now if I go back to the files here and let's refresh, we should be able to see cat.jpeg with the random numbers now, which is the date now and the photo should still work. Here it is. All right. And if you wanted to upload this file into another folder, what you can do is let's remove the date for now. We don't need it. And literally we can just put the folder name here. So let's say images or whatever and then slash and then the file name in here. So if I save this and let's upload one of the big files. So I'm going to choose this one here. It's like, it's fairly large. So it's going to take about to upload. In fact, let's refresh everything. So everything is clean. I'm selecting new file. It's fairly large file upload, uploading. And now if you go to the file uploaded and if I go here for refresh, we should be able to see that we have another folder here called images. And if I click on images, we have the file that I just uploaded. Here it is. And yeah, it's one of the big files, which is pretty cool. Before we end the video, I wanted to show you a really cool library for image optimization and manipulation. So the library is called sharp and you can do quite a lot of things with it. You can resize images. You can optimize images. You can do some color manipulation, channel manipulation and so on. For example, if I click on resize image, you will see that you can do resize, extend, extract, trim and so on. And if I scroll down here, you will see from here some of the values that you can use. And I'm just gonna demonstrate super quickly how you can use this to optimize your images. So the first thing that we need to do is to install the library. So if you use an NPM, you can just do NPM install sharp and they have some other options in here. So let's copy this one. Let's go back to the terminal, right click to install this and then let's do NPM run dev. Okay, your application is back and running. And now let's see how we can optimize our file. Let's include it at the top of our project here. So let's do import sharp and then this is gonna be from sharp like so. So now to use sharp, we're gonna go here to the upload file to S3 and we can already grab the file. So this is just before we're uploading the file. And if you wish to, you can create another function for this but I'm just gonna do a inline here. And in order to do this, so I'm gonna do const file buffer equals and then we can do await because this is an asynchronous function. Then we can use sharp and then inside the sharp, we can put the file that we want to optimize. And now we can start chaining some of the options that we wanna do. So for example, if you do dot, we can do if you do dot jpeg. Inside the jpeg, there is an option for quality. So for example, I can do quality and choose the value. Let's say 90. And then we need to chain one more and do to buffer like so and close this. Okay, now let's try to upload another file. But in this case, let's just remove this folder we don't want that. And let's try to upload another file. So I'm gonna grab one of the big files here. I'm gonna grab this file here. And if I do properties, you'll see that this is 11.6 megabytes. So I'm gonna grab this, open it and then file upload. Okay, it's uploading. Okay, file has been uploaded. Now, if I go to the S3 bucket, if I click on it, let's refresh. Here we have our file, which is 12.1 megabytes. And if I click on it, we'll be able to see it in a new tab here. Here is the file. It is a very big file. Now let's do the same thing with let's say the quality of 50, for example. Save this and let's re-upload the same file. So I'm gonna do choose file, select this one again, file uploading. Okay. And now if you remember, this one was 12.1 megabytes. And if I refresh, because this is just gonna overwrite it, assume I came, yep. As you can see, now this file is 7.4 megabytes. And the quality should be more or less the same. So this was the old one. I'm not gonna refresh here. And let's open a new one. You probably wouldn't be able to tell the difference, but here it is. But yeah, it's gonna be hard to put aside by side. It's gonna be hard to put aside by side. But as you can see, there is barely any difference in quality, but in terms of size, it's quite a huge difference. And you can do a lot more stuff like this. I'm just gonna show you one more example. Let's put them on another line like so, just so they're easy to see. And we can chain more stuff, for example, resize. And inside here, we can put the width. So let's say 800. And let's put the height of 400. I'm not sure what's gonna happen, but let's save this and let's try it out one more time. So I'm gonna grab the file, file upload. So it's going to optimize it and resize if it is. And if we go back, let's see. So last time was 7.4 megabytes. Let's refresh. And now it's 36.9 kilobytes, which is insane. And now let's click on this. And as you can see, the quality of it is totally different now. And let me just save this super quickly. Gonna save it here and let's have a look. See if we put details. Yeah, it seems like it's resized as well. Dimension side 800 by 400, which didn't seem like in the browser, maybe it stretches it. But as you can see, the dimensions have changed and the file size has changed as well, which is pretty cool. And that's gonna be everything from this tutorial.