Introduction#

GitHub this note shows how to handle uploading files to S3 in a next application.

  • Setup project with aws-amplify lib
  • Handle upload using Amplify Storage
  • Handle upload using S3 Client
  • RevalidatePath

Setup Project#

Let create a new nextjs project and add amplify

npx create-next-app@latest

Then add amplify

npm install aws-amplify

We have to create a configuration file named config.ts

export const config = {
aws_cognito_region: process.env.AWS_COGNITO_REGION,
aws_user_pools_id: process.env.AWS_USER_POOLS_ID,
aws_user_pools_web_client_id: process.env.AWS_USER_POOLS_WEB_CLIENT_ID,
aws_cognito_identity_pool_id: process.env.AWS_COGNITO_IDENTITY_POOL_ID,
aws_user_files_s3_bucket_region: process.env.S3_REGION,
aws_user_files_s3_bucket: process.env.BUCKET,
};

Upload Form#

Let create a upload form and a server function to handle the form

import { amplifyHandleUpload, getImages } from "./action";
const Upload = async () => {
const images = await getImages();
return (
<div className="min-h-screen dark:bg-slate-800">
<div className="max-w-3xl mx-auto pt-10">
<form
className="p-5 dark:bg-slate-600 shadow-lg rounded-sm"
action={amplifyHandleUpload}
>
<div>
<input
id="upload"
type="file"
name="upload"
className="text-sm rounded-sm w-full p-2.5 cursor-pointer dark:bg-white bg-slate-100"
></input>
</div>
<button className="bg-orange-400 px-10 py-3 rounded-sm mt-5">
Upload
</button>
</form>
<div className="grid grid-cols-1 gap-5 pt-10">
{images.map((image, id) => (
<div key={id}>
<img src={image} alt={"test"}></img>
</div>
))}
</div>
</div>
</div>
);
};
export default Upload;

To handle uploading file to s3 we can use Amplify Storage or S3 Client. Let use Amplify Storage

"use server";
import { Amplify, Storage } from "aws-amplify";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { fromCognitoIdentityPool } from "@aws-sdk/credential-providers";
import { config, imageNames } from "../config";
import { revalidatePath } from "next/cache";
// amplify handle uploading file
try {
Amplify.configure(config);
console.log("storage configured OK");
} catch (error) {
console.log(error);
}
export const amplifyHandleUpload = async (data: FormData) => {
const file = data.get("upload") as File;
try {
const repsonse = await Storage.put(`${file.name}`, file);
console.log(repsonse);
} catch (error) {
console.log(error);
}
// redirect("/");
revalidatePath("/upload");
};

Finally add revalidate path

// get signed url images
export const getImages = async () => {
"use server";
let images: string[] = [];
for (var name of imageNames) {
try {
let response = await Storage.get(name, {
validateObjectExistence: true,
});
images.push(response);
console.log(response);
} catch (error) {
console.log(error);
}
}
return images;
};

S3 Client#

Alternatively, we can use s3 client to handle uploading files to s3

// s3 client hanlde uploading file
const s3Client = new S3Client({
region: process.env.S3_REGION,
credentials: fromCognitoIdentityPool({
clientConfig: { region: process.env.REGION },
identityPoolId: process.env.IDENTITY_POOL_ID as string,
}),
});
export const s3ClientHandleUpload = async (data: FormData) => {
const file = data.get("upload") as File;
try {
const bytes = await file.arrayBuffer();
const response = await s3Client.send(
new PutObjectCommand({
Bucket: process.env.BUCKET,
Key: `next-amplify-s3/${file.name}`,
Body: Buffer.from(bytes),
})
);
} catch (error) {
console.log(error);
}
};

Reference#