We use tracking cookies to understand how you use the product and help us improve it. For more information on how we store cookies, read our  privacy policy.

Usage & Integration

Learn how to upload and retrieve files from AWS S3.

This page shows practical examples of using AWS S3 in Plainform for file uploads and retrieval.

S3 Client Import

Import the pre-configured S3 client:

Import S3 client
import { s3 } from '@/lib/amazon/s3';
import { env } from '@/env';

Listing Objects

Retrieve files from a specific folder (prefix):

app/api/stripe/orders/route.ts
import { ListObjectsV2Command } from '@aws-sdk/client-s3';
import { s3 } from '@/lib/amazon/s3';
import { env } from '@/env';

export async function GET() {
  const listObjects = await s3.send(
    new ListObjectsV2Command({
      Bucket: env.AWS_S3_BUCKET,
      Prefix: 'mockupUsers/',
      MaxKeys: 5,
    })
  );

  const files = listObjects.Contents?.map(obj => ({
    key: obj.Key,
    size: obj.Size,
    lastModified: obj.LastModified,
    url: `${env.AWS_S3_ENDPOINT}/${obj.Key}`
  }));

  return NextResponse.json({ files });
}

Use case: Plainform uses this to retrieve placeholder user avatars for the orders page.

Uploading Files

Upload a file to S3 and get its URL:

lib/amazon/uploadFile.ts
import { PutObjectCommand } from '@aws-sdk/client-s3';
import { s3 } from '@/lib/amazon/s3';
import { env } from '@/env';

export async function uploadFile(file: File, folder: string) {
  const key = `${folder}/${Date.now()}-${file.name}`;
  
  const command = new PutObjectCommand({
    Bucket: env.AWS_S3_BUCKET,
    Key: key,
    Body: Buffer.from(await file.arrayBuffer()),
    ContentType: file.type,
  });

  await s3.send(command);

  const url = `${env.AWS_S3_ENDPOINT}/${key}`;
  return { key, url };
}

Use in an API route:

app/api/upload/route.ts
import { uploadFile } from '@/lib/amazon/uploadFile';
import { NextResponse } from 'next/server';

export async function POST(req: Request) {
  const formData = await req.formData();
  const file = formData.get('file') as File;

  if (!file) {
    return NextResponse.json({ error: 'No file provided' }, { status: 400 });
  }

  const { key, url } = await uploadFile(file, 'uploads');

  return NextResponse.json({ key, url });
}

Getting Object URLs

Generate public URLs for S3 objects:

Generate URL
import { env } from '@/env';

function getS3Url(key: string): string {
  return `${env.AWS_S3_ENDPOINT}/${key}`;
}

// Example
const avatarUrl = getS3Url('mockupUsers/avatar1.png');
// Returns: https://your-bucket.s3.region.amazonaws.com/mockupUsers/avatar1.png

Signed URLs (Temporary Access)

Generate temporary URLs for private files:

lib/amazon/getSignedUrl.ts
import { GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { s3 } from '@/lib/amazon/s3';
import { env } from '@/env';

export async function getSignedUrl(key: string, expiresIn: number = 3600) {
  const command = new GetObjectCommand({
    Bucket: env.AWS_S3_BUCKET,
    Key: key,
  });

  const url = await getSignedUrl(s3, command, { expiresIn });
  return url;
}

Use case: Generate temporary download links for private files that expire after a set time.

Deleting Files

Remove files from S3:

lib/amazon/deleteFile.ts
import { DeleteObjectCommand } from '@aws-sdk/client-s3';
import { s3 } from '@/lib/amazon/s3';
import { env } from '@/env';

export async function deleteFile(key: string) {
  const command = new DeleteObjectCommand({
    Bucket: env.AWS_S3_BUCKET,
    Key: key,
  });

  await s3.send(command);
}

Using S3 URLs in Components

Fetch and display S3 files in your components:

app/gallery/page.tsx
import { s3 } from '@/lib/amazon/s3';
import { ListObjectsV2Command } from '@aws-sdk/client-s3';
import { env } from '@/env';
import Image from 'next/image';

export default async function GalleryPage() {
  // List images from S3
  const listObjects = await s3.send(
    new ListObjectsV2Command({
      Bucket: env.AWS_S3_BUCKET,
      Prefix: 'gallery/',
    })
  );

  const images = listObjects.Contents?.map(obj => ({
    key: obj.Key!,
    url: `${env.AWS_S3_ENDPOINT}/${obj.Key}`
  })) || [];

  return (
    <div className="grid grid-cols-3 gap-4">
      {images.map(image => (
        <Image
          key={image.key}
          src={image.url}
          alt={image.key}
          width={300}
          height={300}
          className="rounded-lg"
        />
      ))}
    </div>
  );
}

Email Templates

Reference S3 assets in email templates:

emails/OrderStatusTemplate.tsx
import { Img } from '@react-email/components';

export function OrderStatusTemplate() {
  return (
    <Img
      src="https://plainform.s3.eu-central-1.amazonaws.com/fullLogo.png"
      alt="Plainform Logo"
      width={150}
    />
  );
}

Plainform stores email assets (logos, images) on S3 for reliable delivery across email clients.

File Upload Form Example

Complete example with form handling:

components/FileUploadForm.tsx
'use client';

import { useState } from 'react';

export function FileUploadForm() {
  const [file, setFile] = useState<File | null>(null);
  const [uploading, setUploading] = useState(false);
  const [url, setUrl] = useState<string>('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!file) return;

    setUploading(true);

    const formData = new FormData();
    formData.append('file', file);

    const response = await fetch('/api/upload', {
      method: 'POST',
      body: formData,
    });

    const data = await response.json();
    setUrl(data.url);
    setUploading(false);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="file"
        onChange={(e) => setFile(e.target.files?.[0] || null)}
      />
      <button type="submit" disabled={!file || uploading}>
        {uploading ? 'Uploading...' : 'Upload'}
      </button>
      {url && <p>Uploaded: {url}</p>}
    </form>
  );
}

Next Steps

How is this guide ?

Last updated on