Next.js Single Image/Multiple Image upload to AWS s3
Objective: Uploading Single Image or multiple Image using next.js.
I was searching for uploading single image and multiple image from nextjs application to amazon s3 bucket.
You need to setup a public bucket. I will write a post about how to setup or there are many posts about it.
I am diving into nextjs part.
First we need ‘aws-sdk’ in our application
npm -i aws-sdk or npm install aws-sdk
Create separate api for the upload (my preference)
Disclaimer — When uploading files to s3 directly from front end, your AWS credentials are exposed in the network tab. Refrain from uploading files to protected S3 buckets directly from FE. Always use a server to upload files
// pages/api/upload-url.js
import aws from ‘aws-sdk’;
export default async function handler(req, res) {
aws.config.update({
accessKeyId: process.env.ACCESS_KEY,
secretAccessKey: process.env.SECRET_KEY,
region: process.env.REGION,
signatureVersion: ‘v4’,
});
const s3 = new aws.S3();
const post = await s3.createPresignedPost({
Bucket: process.env.BUCKET_NAME,
Fields: {
key: req.query.file,
},
Expires: 60, // seconds
Conditions: [
[‘content-length-range’, 0, 1048576], // up to 1 MB
],
});
res.status(200).json(post);
console.log(res)
}
For single Image Upload
//pages/single-image-upload.js
export default function Upload() {
const uploadPhoto = async (e) => {
const file = e.target.files[0];
const filename = encodeURIComponent(file.name);
const res = await fetch(`/api/upload-url?file=${filename}`);
const { url, fields } = await res.json();
const formData = new FormData();
Object.entries({ …fields, file }).forEach(([key, value]) => { formData.append(key, value); });
const upload = await fetch(url, { method: ‘POST’, body: formData, });
if (upload.ok) {
console.log(‘Uploaded successfully!’);
} else {
console.error(‘Upload failed.’);
} };
return (
<>
<p>Upload a .png or .jpg image (max 1MB).</p>
<input onChange={uploadPhoto} type=”file” accept=”image/png, image/jpeg” /> </>
);
}
multiple image upload
Note: I searched through many posts and videos.. Finally I found AWS don’t support multiple file over a single http request. So We will loop through the single process. Important.. You need to change the fileList to Array to loop through the multiple files
import { useState } from “react”;
export default function Upload() {
const [url, setUrl]= useState([]);
const uploadPhoto = async (e) => {
try{
const myFileList = e.target.files;
const newArr = […myFileList]
const v = await Promise.all(
newArr.map(async (file) => {
const filename = encodeURIComponent(file.name);
const res = await fetch(`/api/upload-url?file=${filename}`);
const { url, fields } = await res.json();
const formData = new FormData();
Object.entries({ …fields, file }).forEach(([key, value]) => {
formData.append(key, value);
});
const upload = await fetch(url, {
method: ‘POST’,
body: formData,
});
if (upload.ok) {
console.log(‘Uploaded successfully!’);
} else {
console.error(‘Upload failed.’);
}
})
)
} catch(e){
console.error(e)
}}
return (
<>
<p>Upload a .png or .jpg image (max 1MB).</p>
<input
onChange={uploadPhoto} type=”file”
accept=”image/png, image/jpeg”
multiple />
//your image will be here after upload. You can use state or map the array after response to show here.
<img src={“”}/>
</>
);}
Reference: AWS SDK for JavaScript 3
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/s3-example-photo-album.html