↳ See other learning resources
AWS S3 Image Upload in Next.js
- Create your <input>:
const [image, setImage]=useState<File | undefined>();
<input
type='file'
accept="image/jpeg,image/png,image/webp,image/gif"
onChange={e=>{
setImage(e.target.files?.[0]);
}}
/>
- Create an S3 bucket and IAM role in the AWS console. a. When creating the bucket, uncheck block all public access b. Set the bucket policy to
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my_bucket_name/*"
}
]
}
c. Set the bucket CORS policy to
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"POST",
"PUT"
],
"AllowedOrigins": [
"http://mywebsite.com",
"https://mywebsite.com",
// "http://localhost:3000" //include for when you are testing but remove it in production
],
"ExposeHeaders": [],
"MaxAgeSeconds": 3000
}
]
d. Create a policy under IAM>Access Management>Policies e. Create a user in IAM and add that policy to the user f. Go to the IAM user's security credentials tab and create an access key
3. Add values from step 2 to your `.env`:
From S3 Bucket config
S3_BUCKET_NAME=my_bucket_name S3_REGION=us-east-1
From IAM User's Access Key
S3_ACCESS_KEY=... S3_SECRET_ACCESS_KEY=...
3. Run `npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner`
4. Implement `getSignedUrl`:
```tsx
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl as s3GetSignedUrl } from '@aws-sdk/s3-request-presigner';
import crypto from 'crypto';
const generateRandomName=()=>crypto.randomBytes(16).toString('hex');
import prisma from '@/data/prisma/client';
const s3=new S3Client({
region: process.env.S3_REGION!,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY!,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
}
});
export async function getSignedUrl(id: string) {
const key=await generateRandomName();
const putObjectCommand=new PutObjectCommand({
Bucket: process.env.S3_BUCKET_NAME,
Key: key
});
const signedUrl=await s3GetSignedUrl(s3, putObjectCommand, { expiresIn: 60 });
const imageUrl=signedUrl.split('?')[0];
// Update your database to include the imageUrl
await prisma.library.update({
where: { id }
data: { imageUrl }
});
return signedUrl;
}
- Create your
onSubmit
handler:
const signedUrl=await getSignedUrl(id); //id is used for updating the database entry
fetch(signedUrl, {
method: 'PUT',
body: image,
headers: {
'Content-Type': image.type,
}
});