Handling Large Files
Best practices for importing 10,000+ rows efficiently
ImportCSV handles large datasets efficiently through virtual scrolling and progressive validation, supporting 10,000+ rows without freezing your browser.
Quick Example
import { CSVImporter } from '@importcsv/react';
import { z } from 'zod';
import { useState } from 'react';
// Define schema with validation and transformations
const transactionSchema = z.object({
transaction_id: z.string().min(1, 'Transaction ID is required'),
date: z.string().datetime(),
customer_email: z.string()
.email('Must be valid email')
.transform(s => s.trim().toLowerCase()),
amount: z.number().nonnegative('Amount must be positive'),
status: z.enum(['pending', 'completed', 'failed', 'refunded']),
notes: z.string().default('N/A').transform(s => s.trim())
});
type Transaction = z.infer<typeof transactionSchema>;
export default function LargeDatasetExample() {
const [importStats, setImportStats] = useState<{
totalRows: number;
sampleData: Transaction[];
timestamp: string;
} | null>(null);
const [isOpen, setIsOpen] = useState(false);
const handleComplete = (data: Transaction[]) => {
setImportStats({
totalRows: data.length,
sampleData: data.slice(0, 5), // Show first 5 rows
timestamp: new Date().toISOString()
});
setIsOpen(false);
console.log(`Successfully imported ${data.length} rows`);
};
return (
<div>
<button
onClick={() => setIsOpen(true)}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
Import Large Dataset
</button>
<CSVImporter
modalIsOpen={isOpen}
modalOnCloseTriggered={() => setIsOpen(false)}
schema={transactionSchema}
validateUnique={['transaction_id']}
onComplete={handleComplete}
primaryColor="#3B82F6"
darkMode={false}
/>
{importStats && (
<div className="mt-4 p-4 border rounded">
<h3 className="font-bold mb-2">Import Statistics</h3>
<p>✅ Successfully imported {importStats.totalRows} rows</p>
<p>🕐 Imported at: {new Date(importStats.timestamp).toLocaleTimeString()}</p>
<h4 className="font-bold mt-4 mb-2">Sample Data (First 5 Rows)</h4>
<pre className="text-xs bg-gray-100 p-2 rounded overflow-auto">
{JSON.stringify(importStats.sampleData, null, 2)}
</pre>
</div>
)}
</div>
);
}How It Works
ImportCSV uses two key techniques to handle large files:
Virtual Scrolling: Renders only visible rows (~20 at a time) instead of all 10,000+ rows, keeping memory usage constant and scrolling smooth at 60fps.
Progressive Validation: First 50 rows validate instantly (< 100ms), while remaining rows validate asynchronously in the background without blocking the UI.
Memory Efficient: Constant memory usage regardless of file size. Only visible rows are kept in the DOM.
Performance Expectations
| Dataset Size | Initial Render | Full Validation | Memory Usage |
|---|---|---|---|
| 100 rows | < 50ms | < 100ms | ~5MB |
| 1,000 rows | < 50ms | < 500ms | ~8MB |
| 5,000 rows | < 50ms | ~2s | ~15MB |
| 10,000 rows | < 50ms | ~4s | ~20MB |
Tested on Chrome 120, MacBook Pro M1
Optimization Tips
1. Use Built-in Validators
// ❌ Complex regex - slower
email: z.string().regex(/^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/)
// ✅ Use built-in validator - faster
email: z.string().email()2. Minimize Transformations
// Only apply necessary transformations
const schema = z.object({
email: z.string()
.email()
.transform(s => s.trim()) // Essential
.transform(s => s.toLowerCase()) // Essential
// Don't add unnecessary transformations
});3. Process Results in Batches
const handleComplete = async (data: Transaction[]) => {
// Process in batches for very large datasets
const BATCH_SIZE = 1000;
for (let i = 0; i < data.length; i += BATCH_SIZE) {
const batch = data.slice(i, i + BATCH_SIZE);
await processBatch(batch);
// Update progress
setProgress((i + BATCH_SIZE) / data.length * 100);
}
};Browser Requirements
For optimal performance with large datasets:
- Chrome 90+ (recommended)
- 4GB+ RAM
- Modern CPU (2015+)
Troubleshooting
File takes too long to validate
- Simplify validators (use built-in types)
- Reduce number of required fields
- Consider server-side validation for 10,000+ rows
Browser becomes unresponsive
- Check file size (should be < 50MB)
- Close other tabs to free memory
- Try Chrome for best performance
Memory issues
- Monitor with Chrome DevTools
- Process data in batches after import
- Consider pagination for display