Overview
Uploadcare File Uploader works seamlessly with Next.js, including support for both the App Router and Pages Router. This guide covers SSR considerations and best practices for Next.js integration.
Installation
Install the File Uploader package:
npm install @uploadcare/file-uploader
App Router (Next.js 13+)
Client Component Setup
Since Web Components require browser APIs, you need to mark your uploader component as a Client Component:
app/components/FileUploader.tsx
'use client' ;
import { useEffect , useRef } from 'react' ;
import * as UC from '@uploadcare/file-uploader' ;
import '@uploadcare/file-uploader/index.css' ;
export default function FileUploader () {
const initialized = useRef ( false );
useEffect (() => {
if ( ! initialized . current ) {
UC . defineComponents ( UC );
initialized . current = true ;
}
}, []);
return (
< div >
< uc-config
ctx-name = "my-uploader"
pubkey = "YOUR_PUBLIC_KEY"
/>
< uc-file-uploader-regular
ctx-name = "my-uploader"
/>
</ div >
);
}
Using in Server Components
Import your Client Component in Server Components:
import FileUploader from './components/FileUploader' ;
export default function Page () {
return (
< main >
< h1 > Upload Files </ h1 >
< FileUploader />
</ main >
);
}
The 'use client' directive is required because Web Components need access to browser APIs that aren’t available during SSR.
Pages Router
Dynamic Import with SSR Disabled
For the Pages Router, use dynamic imports to prevent SSR:
import dynamic from 'next/dynamic' ;
const FileUploader = dynamic (
() => import ( '../components/FileUploader' ),
{ ssr: false }
);
export default function Home () {
return (
< main >
< h1 > Upload Files </ h1 >
< FileUploader />
</ main >
);
}
Create the uploader component:
components/FileUploader.tsx
import { useEffect , useRef } from 'react' ;
import * as UC from '@uploadcare/file-uploader' ;
import '@uploadcare/file-uploader/index.css' ;
export default function FileUploader () {
const initialized = useRef ( false );
useEffect (() => {
if ( ! initialized . current ) {
UC . defineComponents ( UC );
initialized . current = true ;
}
}, []);
return (
< div >
< uc-config
ctx-name = "my-uploader"
pubkey = "YOUR_PUBLIC_KEY"
/>
< uc-file-uploader-regular
ctx-name = "my-uploader"
/>
</ div >
);
}
TypeScript Configuration
Add JSX types support in your TypeScript configuration:
/// < reference types = "@uploadcare/file-uploader/types/jsx" />
Or in tsconfig.json:
{
"compilerOptions" : {
"types" : [ "@uploadcare/file-uploader/types/jsx" ]
}
}
API Routes Integration
Handle uploaded files in API routes:
app/api/upload/route.ts
pages/api/upload.ts
import { NextRequest , NextResponse } from 'next/server' ;
export async function POST ( request : NextRequest ) {
const body = await request . json ();
const { fileUuid , cdnUrl , fileName } = body ;
// Save file information to your database
// Example: await db.files.create({ uuid: fileUuid, url: cdnUrl, name: fileName });
return NextResponse . json ({
success: true ,
fileUuid ,
});
}
Advanced Upload Handler
Create a component that sends upload information to your API:
app/components/FileUploaderWithAPI.tsx
'use client' ;
import { useEffect , useRef } from 'react' ;
import * as UC from '@uploadcare/file-uploader' ;
import '@uploadcare/file-uploader/index.css' ;
export default function FileUploaderWithAPI () {
const ctxProviderRef = useRef < any >( null );
const initialized = useRef ( false );
useEffect (() => {
if ( ! initialized . current ) {
UC . defineComponents ( UC );
initialized . current = true ;
}
}, []);
useEffect (() => {
const ctxProvider = ctxProviderRef . current ;
if ( ! ctxProvider ) return ;
const handleUploadSuccess = async ( e : CustomEvent ) => {
const { uuid , cdnUrl , name } = e . detail ;
try {
const response = await fetch ( '/api/upload' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
fileUuid: uuid ,
cdnUrl ,
fileName: name ,
}),
});
if ( ! response . ok ) {
throw new Error ( 'Failed to save file info' );
}
const data = await response . json ();
console . log ( 'File saved:' , data );
} catch ( error ) {
console . error ( 'Error saving file:' , error );
}
};
ctxProvider . addEventListener ( 'file-upload-success' , handleUploadSuccess );
return () => {
ctxProvider . removeEventListener ( 'file-upload-success' , handleUploadSuccess );
};
}, []);
return (
< div >
< uc-config
ctx-name = "my-uploader"
pubkey = "YOUR_PUBLIC_KEY"
/>
< uc-file-uploader-regular
ctx-name = "my-uploader"
/>
< uc-upload-ctx-provider
ref = { ctxProviderRef }
ctx-name = "my-uploader"
/>
</ div >
);
}
Server Actions (App Router)
Use Next.js Server Actions to handle uploads:
'use server' ;
import { db } from '@/lib/db' ;
export async function saveUploadedFile ( data : {
uuid : string ;
cdnUrl : string ;
name : string ;
}) {
try {
await db . files . create ({
data: {
uuid: data . uuid ,
url: data . cdnUrl ,
name: data . name ,
},
});
return { success: true };
} catch ( error ) {
console . error ( 'Failed to save file:' , error );
return { success: false , error: 'Failed to save file' };
}
}
Use the Server Action in your component:
app/components/FileUploaderWithServerAction.tsx
'use client' ;
import { useEffect , useRef } from 'react' ;
import * as UC from '@uploadcare/file-uploader' ;
import '@uploadcare/file-uploader/index.css' ;
import { saveUploadedFile } from '../actions/upload' ;
export default function FileUploaderWithServerAction () {
const ctxProviderRef = useRef < any >( null );
const initialized = useRef ( false );
useEffect (() => {
if ( ! initialized . current ) {
UC . defineComponents ( UC );
initialized . current = true ;
}
}, []);
useEffect (() => {
const ctxProvider = ctxProviderRef . current ;
if ( ! ctxProvider ) return ;
const handleUploadSuccess = async ( e : CustomEvent ) => {
const { uuid , cdnUrl , name } = e . detail ;
const result = await saveUploadedFile ({ uuid , cdnUrl , name });
if ( result . success ) {
console . log ( 'File saved successfully' );
} else {
console . error ( 'Failed to save file:' , result . error );
}
};
ctxProvider . addEventListener ( 'file-upload-success' , handleUploadSuccess );
return () => {
ctxProvider . removeEventListener ( 'file-upload-success' , handleUploadSuccess );
};
}, []);
return (
< div >
< uc-config
ctx-name = "my-uploader"
pubkey = "YOUR_PUBLIC_KEY"
/>
< uc-file-uploader-regular
ctx-name = "my-uploader"
/>
< uc-upload-ctx-provider
ref = { ctxProviderRef }
ctx-name = "my-uploader"
/>
</ div >
);
}
Environment Variables
Store your Uploadcare public key in environment variables:
NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY = your_public_key_here
Use in your components:
< uc-config
ctx-name = "my-uploader"
pubkey = { process . env . NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY }
/>
Always prefix client-side environment variables with NEXT_PUBLIC_ in Next.js.
Image Optimization
Combine with Next.js Image component for optimized images:
components/UploadedImage.tsx
import Image from 'next/image' ;
interface UploadedImageProps {
cdnUrl : string ;
alt : string ;
}
export default function UploadedImage ({ cdnUrl , alt } : UploadedImageProps ) {
return (
< Image
src = { cdnUrl }
alt = { alt }
width = { 800 }
height = { 600 }
loader = { ({ src , width , quality }) => {
// Use Uploadcare's transformation API
return ` ${ src } -/resize/ ${ width } x/-/quality/ ${ quality || 75 } /` ;
} }
/>
);
}
Best Practices for Next.js
Use Client Components
Always mark components using Web Components with 'use client' in the App Router.
Disable SSR for Pages Router
Use dynamic imports with { ssr: false } when using the Pages Router.
Initialize Once
Call defineComponents() only once per component lifecycle.
Use Environment Variables
Store sensitive configuration like API keys in environment variables.
Handle Loading States
Show loading indicators while the uploader initializes on the client.
Troubleshooting
Hydration Errors
If you encounter hydration errors, ensure your uploader component is either:
Marked as 'use client' (App Router)
Loaded with { ssr: false } (Pages Router)
Window is Not Defined
This error occurs when Web Components code runs on the server. Use the approaches above to ensure client-side only rendering.
CSS Not Loading in Production
Make sure your CSS import is in a component, not in a Server Component:
'use client' ;
import '@uploadcare/file-uploader/index.css' ;
Next Steps
React Integration Learn more about React-specific features
API Routes Next.js Route Handlers documentation
Live Examples View complete Next.js examples
Configuration Explore all configuration options