Skip to Content
FrameworksNext.js

Next.js Integration

This guide explains how to integrate FileZen with Next.js applications using the App Router. We recommend using our dedicated SDK packages for the best experience.

📁 Code Example: View the complete working example at github.com/FileZen/filezen/tree/main/apps/nextjs-app-router 

Installation

Install the required FileZen packages for a Next.js project:

Setup

1. Environment Configuration

Set your FileZen API key as an environment variable. This can be done in your local .env.local file during development or as a system environment variable in production.

.env.local
FILEZEN_API_KEY=your_api_key_here

The FileZen SDK automatically detects the FILEZEN_API_KEY environment variable for server-side operations, so no additional configuration is needed in your API routes.

2. API Route

The API route is crucial for security, as it keeps your API key on the server and prevents it from being exposed in the client-side code.

Create an API route to handle file uploads and other operations. The createZenNextRouter function from @filezen/next simplifies this process by creating the necessary POST and DELETE handlers.

app/api/upload/route.ts
import { ZenApi } from '@filezen/js'; import { createZenNextRouter } from '@filezen/next'; // The ZenApi class will automatically pick up the FILEZEN_API_KEY from environment variables. const zenApi = new ZenApi(); export const { POST, DELETE } = createZenNextRouter(zenApi);

By default, the client expects this route at /api/upload. You should create this file at app/api/upload/route.ts. If you wish to use a different path, you can create the route file elsewhere and specify the new path in the ZenClientProvider.

Request Validation Middleware (Optional)

You can add request validation middleware to verify requests before generating signed URLs for file uploads. This is useful for implementing authentication, authorization, or other custom validation logic.

app/api/upload/route.ts
import { ZenApi, ZenError } from '@filezen/js'; import { createZenNextRouter } from '@filezen/next'; import { NextRequest } from 'next/server'; const zenApi = new ZenApi(); const requestMiddleware = async (request: NextRequest) => { /** * Here you can verify request, e.g - check user authentication: * const user = await getUserFromRequest(request); * if (!user) { * throw new ZenError(401, 'Unauthorized'); * } * return { userId: user.id } */ }; export const { POST, DELETE } = createZenNextRouter(zenApi, { onRequest: requestMiddleware, });

The middleware function can:

  • Return additional metadata that will be available in the request context
  • Throw a ZenError to reject the request with a specific status code and message
  • Return void or undefined if no additional processing is needed

3. Provider Setup

Wrap your application’s root layout with the ZenClientProvider. This makes the ZenClient instance available to all components in your application via the useZenClient hook.

When using @filezen/next, you do not need to pass any props to the provider if you use the default API route path (/api/upload).

app/layout.tsx
import { ZenClientProvider } from '@filezen/react'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <ZenClientProvider>{children}</ZenClientProvider> </body> </html> ); }

If you have customized the API route path, you must provide the signUrl prop to the ZenClientProvider.

app/layout.tsx
import { ZenClientProvider } from '@filezen/react'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <ZenClientProvider signUrl="/api/your-custom-path">{children}</ZenClientProvider> </body> </html> ); }

Using the Hook

Once the provider is set up, you can use the useZenClient hook in any client component to access the upload functionality:

import { useZenClient } from '@filezen/react'; // Get the client instance const zenClient = useZenClient(); // Upload a file const result = await zenClient.upload(file); if (result.file) { console.log('Upload successful:', result.file.url); }

File Upload Component Example

With the provider and API route set up, you can now create a client component to handle file uploads. The useZenClient hook provides a zenClient instance that communicates with your API route.

components/FileUpload.tsx
'use client'; import { ZenFile } from '@filezen/js'; import { useZenClient } from '@filezen/react'; import React from 'react'; import { useDropzone } from 'react-dropzone'; export const FileUpload = () => { const zenClient = useZenClient(); const [isUploading, setIsUploading] = React.useState(false); const [uploadResult, setUploadResult] = React.useState<ZenFile | null>(null); const handleUpload = async (file: File) => { setIsUploading(true); const result = await zenClient.upload(file); setIsUploading(false); if (result.file) { setUploadResult(result.file); } else { console.error(result.error); } }; const onDrop = React.useCallback((acceptedFiles: File[]) => { if (acceptedFiles.length > 0) { handleUpload(acceptedFiles[0]); } }, []); const { getRootProps, getInputProps } = useDropzone({ onDrop }); return ( <div> <div {...getRootProps()} style={{ border: '2px dashed #ccc', padding: '20px', cursor: 'pointer' }}> <input {...getInputProps()} /> <p>Drag 'n' drop some files here, or click to select files</p> </div> {isUploading && <p>Uploading...</p>} {uploadResult && ( <div> <p>File uploaded successfully!</p> <a href={uploadResult.url} target="_blank" rel="noopener noreferrer"> <img src={uploadResult.url} alt="Upload preview" style={{ maxWidth: '200px' }} /> </a> </div> )} </div> ); };

The zenClient.upload() method requests a signed URL from your API route (/api/upload), then uploads the file directly to FileZen from the client side. This reduces traffic usage on your server since files don’t pass through your backend.

Last updated on
© 2026 FileZen. All rights reserved.