typescriptintermediate
File Upload with Server Action
Handle file uploads using server actions with validation, size limits, and storage.
typescriptPress ⌘/Ctrl + Shift + C to copy
'use server';
import { writeFile, mkdir } from 'fs/promises';
import { join } from 'path';
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
interface UploadResult {
success: boolean;
url?: string;
error?: string;
}
export async function uploadFile(formData: FormData): Promise<UploadResult> {
const file = formData.get('file') as File;
if (!file || file.size === 0) {
return { success: false, error: 'No file provided' };
}
if (file.size > MAX_FILE_SIZE) {
return { success: false, error: 'File too large (max 5MB)' };
}
if (!ALLOWED_TYPES.includes(file.type)) {
return { success: false, error: 'File type not allowed' };
}
try {
const bytes = await file.arrayBuffer();
const buffer = Buffer.from(bytes);
// Generate unique filename
const ext = file.name.split('.').pop();
const filename = `${Date.now()}-${Math.random().toString(36).slice(2)}.${ext}`;
const uploadDir = join(process.cwd(), 'public', 'uploads');
await mkdir(uploadDir, { recursive: true });
await writeFile(join(uploadDir, filename), buffer);
return {
success: true,
url: `/uploads/${filename}`,
};
} catch {
return { success: false, error: 'Upload failed' };
}
}
// Client component:
// 'use client';
// export function UploadForm() {
// const [result, setResult] = useState<UploadResult | null>(null);
// return (
// <form action={async (fd) => setResult(await uploadFile(fd))}>
// <input type="file" name="file" accept="image/*,.pdf" />
// <button type="submit">Upload</button>
// {result?.error && <p className="text-red-500">{result.error}</p>}
// {result?.url && <img src={result.url} alt="Uploaded" />}
// </form>
// );
// }Use Cases
- image uploads
- document uploads
- avatar changes
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
typescriptintermediate
Server Action with Form Validation
Next.js Server Action handling form submissions with validation, error messages, and redirect on success.
Best for: Blog post creation
#server-actions#forms
typescriptintermediate
Next.js Server Actions with Forms
Use Server Actions for form handling with validation, optimistic updates, and error handling.
Best for: Form submissions without API routes
#nextjs#server-actions
typescriptadvanced
Form with Server Action Validation
Build forms using Next.js server actions with server-side validation, error handling, and useActionState.
Best for: Contact form submissions
#nextjs#forms
typescriptintermediate
Server Action Validation with Zod
Validate form data in server actions using Zod schemas with type-safe error handling.
Best for: contact forms
#nextjs#zod