Uploading Files with Next.js and Edge Store

Lakindu Banneheka
4 min readMay 27, 2024

--

Uploading files in a modern web application can be a complex task, but with the right tools, it can be streamlined. In this article, we will explore how to set up file uploads using Next.js and Edge Store, a powerful serverless storage solution. We will walk through the steps of setting up the backend and frontend, ensuring a smooth integration and user experience.

Prerequisites

Before we begin, ensure you have Node.js installed on your machine. We’ll be using Next.js, a React framework, and Edge Store for file storage.

Step 1: Setting Up Next.js and Edge Store

First, create a new Next.js project if you haven’t already:

npx create-next-app@latest my-upload-app
cd my-upload-app

Next, install the necessary dependencies:

npm install @edgestore/server @edgestore/react zod

Step 2: Configuring the Edge Store Backend

Create a new file at app/api/edgestore/[...edgestore]/route.ts with the following content:

import { initEdgeStore } from '@edgestore/server';
import { createEdgeStoreNextHandler } from '@edgestore/server/adapters/next/app';

const es = initEdgeStore.create();

/**
* This is the main router for the Edge Store buckets.
*/
const edgeStoreRouter = es.router({
publicFiles: es.fileBucket(),
});

const handler = createEdgeStoreNextHandler({
router: edgeStoreRouter,
});

export { handler as GET, handler as POST };

/**
* This type is used to create the type-safe client for the frontend.
*/
export type EdgeStoreRouter = typeof edgeStoreRouter;

This code sets up the Edge Store router, which will handle file uploads.

Step 3: Setting Up the Frontend Client

Next, create a file at lib/edgestore.ts:

"use client"
import { EdgeStoreRouter } from "@/app/api/edgestore/[...edgestore]/route"
import { createEdgeStoreProvider } from "@edgestore/react"

export const { EdgeStoreProvider, useEdgeStore } = createEdgeStoreProvider<EdgeStoreRouter>();

This code initializes the Edge Store client for the frontend.

Step 4: Integrating Edge Store Provider in Layout

Update app/layout.tsx to include the Edge Store provider:

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { EdgeStoreProvider } from "@/lib/edgestore";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
<EdgeStoreProvider>
{children}
</EdgeStoreProvider>
</body>
</html>
);
}

Step 5: Configuring Environment Variables

Create an account on Edge Store and create a new project. Copy the access keys and save them in a .env file in the root of your project:

EDGE_STORE_ACCESS_KEY=your_access_key
EDGE_STORE_SECRET_KEY=your_secret_key

Step 6: Creating the Upload Component

Now, let’s create a page that allows users to upload files. Create or update the app/page.tsx with the following content:

"use client"
import { useEdgeStore } from "@/lib/edgestore";
import Link from "next/link";
import { useState } from "react";

export default function Home() {
const [file, setFile] = useState<File | null>(null);
const [urls, setUrls] = useState<{ url: string, thumbnailUrl: string | null }>();

const { edgestore } = useEdgeStore();

const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files.length > 0) {
setFile(event.target.files[0]);
}
};

const handleUpload = async () => {
if (file) {
console.log('Uploading:', file.name);
const res = await edgestore.publicFiles.upload({ file });
console.log(res);
setUrls({
url: res.url,
thumbnailUrl: res.thumbnailUrl,
});
}
};

return (
<div className="flex flex-col items-center p-4 border border-dashed border-gray-300 rounded-lg">
<input
type="file"
onChange={handleFileChange}
className="mb-4"
/>
{file && (
<div className="mb-4 text-gray-700">
Selected file: {file.name}
</div>
)}
<button
onClick={handleUpload}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Upload
</button>
{urls?.url && <Link href={urls.url} target="_blank">URL</Link>}
{urls?.thumbnailUrl && <Link href={urls.thumbnailUrl} target="_blank">THUMBNAIL</Link>}
</div>
);
}

Step 7: Adding a Progress Bar

To enhance user experience, we can add a progress bar to show the upload progress. Update the app/page.tsx:

"use client"
import { useEdgeStore } from "@/lib/edgestore";
import Link from "next/link";
import { useState } from "react";

export default function Home() {
const [file, setFile] = useState<File | null>(null);
const [progress, setProgress] = useState(0);
const [urls, setUrls] = useState<{ url: string, thumbnailUrl: string | null }>();

const { edgestore } = useEdgeStore();

const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files.length > 0) {
setFile(event.target.files[0]);
}
};

const handleUpload = async () => {
if (file) {
console.log('Uploading:', file.name);
const res = await edgestore.publicFiles.upload({
file,
onProgressChange: (progress) => {
setProgress(progress);
}
});
console.log(res);
setUrls({
url: res.url,
thumbnailUrl: res.thumbnailUrl,
});
}
};

return (
<div className="flex flex-col items-center p-4 border border-dashed border-gray-300 rounded-lg">
<input
type="file"
onChange={handleFileChange}
className="mb-4"
/>
<div className="h-[6px] w-44 border rounded overflow-hidden">
<div
className="h-full bg-blue-500 transition-all duration-150"
style={{
width: `${progress}%`
}}
/>
</div>
{file && (
<div className="mb-4 text-gray-700">
Selected file: {file.name}
</div>
)}
<button
onClick={handleUpload}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 mt-5"
>
Upload
</button>
{urls?.url && <Link href={urls.url} target="_blank">URL</Link>}
{urls?.thumbnailUrl && <Link href={urls.thumbnailUrl} target="_blank">THUMBNAIL</Link>}
</div>
);
}

With these steps, you’ve set up a complete file upload solution using Next.js and Edge Store. This integration allows you to handle file uploads efficiently, providing feedback to users through progress bars and links to uploaded files. This setup is scalable and can be customized further based on your application’s requirements.

Happy coding!

--

--

Lakindu Banneheka
Lakindu Banneheka

Written by Lakindu Banneheka

I'm a undergraduate in Electronic and computer science in university of Kelaniya, Sri Lanka.

No responses yet