How to Upload Files Using Putfile.dev
File uploads are a common requirement in modern web applications, but implementing them can be surprisingly complex. Putfile.dev eliminates this complexity by providing a simple, powerful API that handles all the heavy lifting. In this comprehensive guide, you'll learn how to implement file uploads in your application—from basic setup to production-ready implementations.
What You'll Build
By the end of this tutorial, you'll know how to:
- Set up a Putfile.dev account and generate API keys
- Implement basic file uploads with vanilla JavaScript
- Build a file upload component in React
- Handle file uploads in Next.js applications
- Implement drag-and-drop functionality
- Display upload progress and handle errors
Prerequisites
Before you begin, make sure you have:
- Node.js (v16 or higher) installed
- Basic understanding of JavaScript/TypeScript
- A Putfile.dev account (sign up at putfile.dev)
Step 1: Initial Setup
Create Your Putfile.dev Account
- Visit putfile.dev and sign up for a free account
- Navigate to your dashboard
- Generate a new API key
- Copy and save your API key securely
Install the Putfile Library
npm install @putfiledev/putfile
Or with yarn:
yarn add @putfiledev/putfile
Step 2: Basic File Upload with Vanilla JavaScript
Let's start with the simplest implementation—a basic file upload using vanilla JavaScript.
HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Putfile Upload Demo</title>
</head>
<body>
<div class="upload-container">
<input type="file" id="fileInput" />
<button id="uploadBtn">Upload File</button>
<div id="status"></div>
<div id="result"></div>
</div>
<script type="module" src="./upload.js"></script>
</body>
</html>
JavaScript Implementation
import { putfile } from '@putfiledev/putfile';
// Initialize with your API key
const PUTFILE_API_KEY = 'your_api_key_here';
const fileInput = document.getElementById('fileInput');
const uploadBtn = document.getElementById('uploadBtn');
const status = document.getElementById('status');
const result = document.getElementById('result');
uploadBtn.addEventListener('click', async () => {
const file = fileInput.files[0];
if (!file) {
status.textContent = 'Please select a file first';
return;
}
try {
status.textContent = 'Uploading...';
const response = await putfile(file, {
apiKey: PUTFILE_API_KEY,
});
status.textContent = 'Upload successful!';
result.innerHTML = `
<p>File URL: <a href="${response.url}" target="_blank">${response.url}</a></p>
<p>File ID: ${response.id}</p>
`;
} catch (error) {
status.textContent = `Upload failed: ${error.message}`;
console.error('Upload error:', error);
}
});
That's it! You now have a working file upload system.
Step 3: React Implementation
For React applications, let's build a reusable file upload component with progress tracking.
Basic React Component
import { useState } from 'react';
import { putfile } from '@putfiledev/putfile';
export function FileUploader() {
const [file, setFile] = useState(null);
const [uploading, setUploading] = useState(false);
const [uploadedUrl, setUploadedUrl] = useState('');
const [error, setError] = useState('');
const handleFileChange = (e) => {
setFile(e.target.files[0]);
setError('');
};
const handleUpload = async () => {
if (!file) {
setError('Please select a file');
return;
}
setUploading(true);
setError('');
try {
const result = await putfile(file, {
apiKey: process.env.NEXT_PUBLIC_PUTFILE_API_KEY,
});
setUploadedUrl(result.url);
setFile(null);
} catch (err) {
setError(`Upload failed: ${err.message}`);
} finally {
setUploading(false);
}
};
return (
<div className="file-uploader">
<input
type="file"
onChange={handleFileChange}
disabled={uploading}
/>
<button
onClick={handleUpload}
disabled={!file || uploading}
>
{uploading ? 'Uploading...' : 'Upload File'}
</button>
{error && <p className="error">{error}</p>}
{uploadedUrl && (
<div className="success">
<p>File uploaded successfully!</p>
<a href={uploadedUrl} target="_blank" rel="noopener noreferrer">
View File
</a>
</div>
)}
</div>
);
}
Advanced Component with Progress
import { useState } from 'react';
import { putfile } from '@putfiledev/putfile';
export function AdvancedFileUploader() {
const [file, setFile] = useState(null);
const [progress, setProgress] = useState(0);
const [uploading, setUploading] = useState(false);
const [uploadedUrl, setUploadedUrl] = useState('');
const handleUpload = async () => {
if (!file) return;
setUploading(true);
setProgress(0);
try {
const result = await putfile(file, {
apiKey: process.env.NEXT_PUBLIC_PUTFILE_API_KEY,
onProgress: (progressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
setProgress(percentCompleted);
},
});
setUploadedUrl(result.url);
} catch (error) {
console.error('Upload failed:', error);
} finally {
setUploading(false);
}
};
return (
<div>
<input
type="file"
onChange={(e) => setFile(e.target.files[0])}
disabled={uploading}
/>
<button onClick={handleUpload} disabled={!file || uploading}>
Upload
</button>
{uploading && (
<div className="progress-bar">
<div
className="progress-fill"
style={{ width: `${progress}%` }}
>
{progress}%
</div>
</div>
)}
{uploadedUrl && <p>File URL: {uploadedUrl}</p>}
</div>
);
}
Step 4: Next.js Implementation
For Next.js applications, you can implement file uploads using both client-side and server-side approaches.
Client-Side Upload
'use client';
import { useState } from 'react';
import { putfile } from '@putfiledev/putfile';
export default function UploadPage() {
const [selectedFile, setSelectedFile] = useState(null);
const [uploadResult, setUploadResult] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
if (!selectedFile) return;
try {
const result = await putfile(selectedFile, {
apiKey: process.env.NEXT_PUBLIC_PUTFILE_API_KEY,
});
setUploadResult(result);
} catch (error) {
console.error('Upload error:', error);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="file"
onChange={(e) => setSelectedFile(e.target.files[0])}
/>
<button type="submit">Upload</button>
{uploadResult && (
<div>
<p>Success! File uploaded to:</p>
<a href={uploadResult.url}>{uploadResult.url}</a>
</div>
)}
</form>
);
}
Server Action Implementation
// app/actions.ts
'use server';
import { putfile } from '@putfiledev/putfile';
export async function uploadFile(formData: FormData) {
const file = formData.get('file') as File;
if (!file) {
return { error: 'No file provided' };
}
try {
const result = await putfile(file, {
apiKey: process.env.PUTFILE_API_KEY,
});
return { success: true, url: result.url };
} catch (error) {
return { error: 'Upload failed' };
}
}
// app/upload/page.tsx
'use client';
import { uploadFile } from '../actions';
export default function ServerUploadPage() {
const handleSubmit = async (formData: FormData) => {
const result = await uploadFile(formData);
if (result.success) {
console.log('File uploaded:', result.url);
} else {
console.error('Error:', result.error);
}
};
return (
<form action={handleSubmit}>
<input type="file" name="file" required />
<button type="submit">Upload File</button>
</form>
);
}
Step 5: Drag and Drop Implementation
Enhance user experience with drag-and-drop functionality:
import { useState } from 'react';
import { putfile } from '@putfiledev/putfile';
export function DragDropUploader() {
const [isDragging, setIsDragging] = useState(false);
const [uploadedUrl, setUploadedUrl] = useState('');
const handleDragOver = (e) => {
e.preventDefault();
setIsDragging(true);
};
const handleDragLeave = (e) => {
e.preventDefault();
setIsDragging(false);
};
const handleDrop = async (e) => {
e.preventDefault();
setIsDragging(false);
const files = e.dataTransfer.files;
if (files.length === 0) return;
try {
const result = await putfile(files[0], {
apiKey: process.env.NEXT_PUBLIC_PUTFILE_API_KEY,
});
setUploadedUrl(result.url);
} catch (error) {
console.error('Upload error:', error);
}
};
return (
<div
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
style={{
border: `2px dashed ${isDragging ? '#0070f3' : '#ccc'}`,
padding: '40px',
textAlign: 'center',
backgroundColor: isDragging ? '#f0f8ff' : 'white',
}}
>
<p>Drag and drop a file here, or click to select</p>
<input
type="file"
onChange={async (e) => {
const file = e.target.files[0];
if (file) {
const result = await putfile(file, {
apiKey: process.env.NEXT_PUBLIC_PUTFILE_API_KEY,
});
setUploadedUrl(result.url);
}
}}
style={{ display: 'block', margin: '20px auto' }}
/>
{uploadedUrl && (
<div>
<p>✅ File uploaded successfully!</p>
<a href={uploadedUrl} target="_blank" rel="noopener">
{uploadedUrl}
</a>
</div>
)}
</div>
);
}
Best Practices
1. Environment Variables
Never hardcode your API key. Use environment variables:
# .env.local
NEXT_PUBLIC_PUTFILE_API_KEY=your_api_key_here
2. File Validation
Always validate files before uploading:
function validateFile(file) {
const maxSize = 10 * 1024 * 1024; // 10MB
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
if (file.size > maxSize) {
throw new Error('File is too large (max 10MB)');
}
if (!allowedTypes.includes(file.type)) {
throw new Error('File type not allowed');
}
return true;
}
3. Error Handling
Implement comprehensive error handling:
try {
const result = await putfile(file, { apiKey });
// Success handling
} catch (error) {
if (error.response?.status === 413) {
console.error('File too large');
} else if (error.response?.status === 401) {
console.error('Invalid API key');
} else {
console.error('Upload failed:', error.message);
}
}
4. User Feedback
Provide clear feedback throughout the upload process:
- Show loading states during upload
- Display progress bars for large files
- Show success/error messages
- Provide uploaded file URLs
Common Pitfalls to Avoid
| Issue | Problem | Solution |
|---|---|---|
| Exposed API Keys | Hardcoding API keys in frontend | Use environment variables |
| No File Validation | Uploading invalid/large files | Validate before upload |
| Poor UX | No upload progress feedback | Implement progress tracking |
| No Error Handling | Silent failures confuse users | Show clear error messages |
Next Steps
Now that you know how to upload files with Putfile.dev, you can:
- Customize upload options: Add metadata, set custom filenames, configure expiration
- Implement image optimization: Use Putfile's built-in image transformation features
- Build file management: Create galleries, file browsers, and deletion workflows
- Explore advanced features: Learn about webhooks, CDN integration, and analytics
Conclusion
Putfile.dev makes file uploads simple and reliable. With just a few lines of code, you've implemented a production-ready file upload system that scales automatically, includes built-in security, and provides a great user experience.
Ready to build something amazing? Get started with Putfile.dev →