Using Next.js & Node.js AWS SDK (@aws-sdk/client-s3) with QuixiCloud Storage: Complete 2026 Guide
Using Next.js & Node.js AWS SDK (@aws-sdk/client-s3) with QuixiCloud Storage: Complete 2026 Guide
The JavaScript and TypeScript ecosystem stands at the center of modern web engineering. Frameworks like Next.js (by Vercel) and standalone Node.js runtimes power millions of SaaS dashboards, e-commerce applications, and digital media platforms globally.
When a Next.js application handles user uploads—such as profile pictures, PDF invoices, or video files—the modern industry standard is the modular AWS SDK for JavaScript v3 (@aws-sdk/client-s3).
Because QuixiCloud M-S3 is built to adhere strictly to official S3 API protocols, you can utilize the official AWS SDK v3 without installing proprietary wrappers or custom drivers.
In this practical technical guide, we walk through configuring the modular AWS SDK v3 in a Next.js 14/15 App Router project, creating direct-to-S3 presigned uploads with Server Actions, and rendering uploaded assets with blazing-fast edge performance.
1. Installing Required Packages
In your Next.js project directory, install the modular AWS SDK v3 client and request presigner packages:
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
2. Environment Configuration
Add your QuixiCloud M-S3 connection credentials to .env.local:
# .env.local
QUIXICLOUD_S3_ENDPOINT=https://s3.quixicloud.com
QUIXICLOUD_ACCESS_KEY_ID=qx_live_YOUR_KEY
QUIXICLOUD_SECRET_ACCESS_KEY=qx_sec_YOUR_SECRET
QUIXICLOUD_BUCKET_NAME=production-app-assets
QUIXICLOUD_REGION=us-east-1
Security Rule: Never expose access keys to client-side bundles with
NEXT_PUBLIC_. Keep credentials strictly scoped to the server runtime.
3. Creating a Singleton S3 Client Instance
Construct a reusable client instance in src/lib/s3Client.ts:
// src/lib/s3Client.ts
import { S3Client } from "@aws-sdk/client-s3";
if (!process.env.QUIXICLOUD_ACCESS_KEY_ID || !process.env.QUIXICLOUD_SECRET_ACCESS_KEY) {
throw new Error("Missing QuixiCloud S3 environment variables.");
}
export const s3Client = new S3Client({
endpoint: process.env.QUIXICLOUD_S3_ENDPOINT || "https://s3.quixicloud.com",
region: process.env.QUIXICLOUD_REGION || "us-east-1",
credentials: {
accessKeyId: process.env.QUIXICLOUD_ACCESS_KEY_ID,
secretAccessKey: process.env.QUIXICLOUD_SECRET_ACCESS_KEY,
},
forcePathStyle: true, // Recommended for custom S3 endpoints
});
4. Generating Direct Presigned Upload URLs via Server Actions
With Next.js App Router, the cleanest architectural pattern is generating a short-lived Presigned Upload URL on the server, enabling the client browser to upload directly to QuixiCloud M-S3 via HTTP PUT.
Create a Server Action in src/app/actions/upload.ts:
// src/app/actions/upload.ts
"use server";
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { s3Client } from "@/lib/s3Client";
import { v4 as uuidv4 } from "uuid";
export async function getPresignedUploadUrl(filename: string, fileType: string) {
try {
const fileExtension = filename.split(".").pop();
const uniqueKey = `uploads/${uuidv4()}.${fileExtension}`;
const command = new PutObjectCommand({
Bucket: process.env.QUIXICLOUD_BUCKET_NAME,
Key: uniqueKey,
ContentType: fileType,
});
// Generate signed URL valid for 5 minutes (300 seconds)
const presignedUrl = await getSignedUrl(s3Client, command, { expiresIn: 300 });
return {
success: true,
uploadUrl: presignedUrl,
fileKey: uniqueKey,
};
} catch (error) {
console.error("Failed to generate presigned upload URL:", error);
return { success: false, error: "Failed to generate upload URL." };
}
}
5. Building the Client-Side Upload Component
Now build a client component in src/components/FileUpload.tsx that requests the presigned ticket and streams the file directly to QuixiCloud:
// src/components/FileUpload.tsx
"use client";
import { useState } from "react";
import { getPresignedUploadUrl } from "@/app/actions/upload";
export default function FileUpload() {
const [file, setFile] = useState<File | null>(null);
const [uploading, setUploading] = useState(false);
const [uploadedKey, setUploadedKey] = useState<string | null>(null);
const handleUpload = async () => {
if (!file) return;
setUploading(true);
try {
// 1. Fetch pre-signed authorization from Next.js server action
const res = await getPresignedUploadUrl(file.name, file.type);
if (!res.success || !res.uploadUrl) {
throw new Error(res.error || "Failed to retrieve upload URL");
}
// 2. Stream binary payload directly from browser to QuixiCloud M-S3
const uploadResponse = await fetch(res.uploadUrl, {
method: "PUT",
headers: { "Content-Type": file.type },
body: file,
});
if (!uploadResponse.ok) {
throw new Error("Direct S3 upload failed.");
}
setUploadedKey(res.fileKey || null);
alert("File uploaded successfully to QuixiCloud M-S3!");
} catch (err: any) {
alert("Upload failed: " + err.message);
} finally {
setUploading(false);
}
};
return (
<div className="p-6 border rounded-xl max-w-md bg-white shadow-sm">
<h3 className="text-lg font-bold mb-4">Direct Next.js S3 Upload</h3>
<input
type="file"
onChange={(e) => setFile(e.target.files?.[0] || null)}
className="mb-4 block w-full text-sm text-gray-500"
/>
<button
onClick={handleUpload}
disabled={!file || uploading}
className="px-4 py-2 bg-indigo-600 text-white font-semibold rounded-lg disabled:opacity-50"
>
{uploading ? "Uploading..." : "Upload to QuixiCloud"}
</button>
{uploadedKey && (
<p className="mt-4 text-sm text-green-600">
Uploaded Key: <code className="bg-gray-100 p-1 rounded">{uploadedKey}</code>
</p>
)}
</div>
);
}
6. Next.js Image Optimization Configuration
If your Next.js application serves user-uploaded images via the <Image /> component, whitelist the QuixiCloud hostname in next.config.js:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 's3.quixicloud.com',
pathname: '/**',
},
],
},
};
module.exports = nextConfig;
Why Full-Stack Engineers Choose QuixiCloud M-S3
- Eliminate Outbound Bandwidth Bills: With 1.5× to 3.0× bundled egress bandwidth, your Next.js application will never trigger unexpected multi-hundred-dollar data transfer invoices.
- Predictable Flat Pricing: Individual developer plans start at just $4.99/month for 1 TB with 2.5 Million included API operations.
- Frictionless Integration: Standard AWS SDK v3 compatibility ensures zero architectural lock-in.
Equip your Next.js applications with scalable, high-performance object storage. Launch your first bucket at aws.quixicloud.com.
Written by QuixiCloud Team
The QuixiCloud Engineering Team is dedicated to building secure, scalable, and privacy-first cloud storage solutions.
