Bulk
Page for processing multiple addresses at once (up to 1,000), returning municipality information for each address.
Bulk Processing Page (app/bulk/)
Page for processing multiple addresses at once (up to 1,000), returning municipality information for each address.
Purpose
Enables batch geocoding for:
- Business registration systems (process entire employee roster)
- Data migration (normalize existing address databases)
- Bulk validation (verify address data quality)
- Reporting (generate municipality statistics)
Route
/bulk - Bulk Address Processing
Features
Input Methods
- Text Area Paste: Copy/paste addresses (one per line)
- CSV Upload: Upload file with address column
- Example Data: Load sample addresses for testing
Processing
- Parallel Execution: Multiple addresses geocoded simultaneously
- Rate Limiting: Respects API rate limits automatically
- Progress Tracking: Real-time progress bar during processing
- Partial Success: Continues even if some addresses fail
Output
- Results Table: Municipality, formatted address, coordinates for each input
- Error Highlighting: Failed addresses marked with error messages
- CSV Export: Download results with all data columns
- Copy to Clipboard: Copy results as tab-separated values
Usage Flow
- Navigate to
/bulk - Enter addresses (paste or upload CSV)
- Click "Process Addresses"
- View progress bar (updates in real-time)
- Review results table
- Download CSV or copy to clipboard
Input Format
Text Area (Line-Separated)
323 Dr Martin Luther King Jr Blvd, Newark, NJ 07102
125 West State Street, Trenton, NJ 08608
354 Stockton Street, Princeton, NJ 08540
CSV Upload
address
"323 Dr Martin Luther King Jr Blvd, Newark, NJ 07102"
"125 West State Street, Trenton, NJ 08608"
"354 Stockton Street, Princeton, NJ 08540"
Requirements:
- Header row must include column named
address(case-insensitive) - Each row contains one address
- Maximum 1,000 addresses per file
Output Format
Results Table
| Address | Municipality | County | Formatted Address | Status |
|---|---|---|---|---|
| 323 Dr MLK Jr Blvd... | Newark | Essex | 323 DR MARTIN LUTHER KING... | ✅ Success |
| 125 West State St... | Trenton | Mercer | 125 WEST STATE STREET... | ✅ Success |
| Invalid address | - | - | - | ❌ Not found |
CSV Export
input_address,municipality,county,formatted_address,latitude,longitude,status,error
"323 Dr Martin Luther King Jr Blvd, Newark, NJ 07102",Newark,Essex,"323 DR MARTIN LUTHER KING JR BLVD, NEWARK, NJ, 07102",40.740623,-74.175383,success,
"Invalid address",,,,,,,error,"Address not found"
Limits and Performance
| Metric | Value |
|---|---|
| Maximum addresses | 1,000 per request |
| Processing time | ~2-5 seconds per 100 addresses |
| Rate limiting | Enforced by API adapter |
| Cache hit rate | 60-80% for common addresses |
| Memory usage | < 50MB for 1,000 addresses |
Error Handling
Address-Level Errors
Individual addresses may fail while others succeed:
- Address Not Found: Invalid or non-existent address
- Validation Error: Malformed input (empty, too long, XSS)
- API Timeout: NJ API didn't respond in time
Failed addresses appear in results table with error details.
Request-Level Errors
Entire request fails if:
- Input exceeds 1,000 addresses
- No addresses provided
- Invalid file format
- Server error during processing
UI Components
- Address Input: Large textarea or file upload
- Process Button: Triggers bulk geocoding server action
- Progress Bar: Shows completion percentage
- Results Table: Displays all results with status indicators
- Export Buttons: Download CSV or copy to clipboard
- Error Summary: Count of successful/failed addresses
Server Action
Page calls geocodeAddressesBulk() server action:
import { geocodeAddressesBulk } from "@/app/actions/bulk-geocoding";
const addresses = ["Address 1", "Address 2", "Address 3"];
const results = await geocodeAddressesBulk(addresses);
if (results.success) {
// results.data is array of GeocodingResult | null
results.data.forEach((result, index) => {
if (result) {
console.log(`${addresses[index]} → ${result.municipality.name}`);
} else {
console.log(`${addresses[index]} → FAILED`);
}
});
}
Accessibility
- Keyboard Navigation: Tab through input, buttons, results
- Screen Reader Support: ARIA labels on all interactive elements
- Progress Announcements: Live region updates for status changes
- Error Messages: Associated with specific input fields
- Focus Management: Focus moves to results after processing
Testing
Bulk processing is tested with:
- Unit Tests: Server action with various input sizes
- Integration Tests: Full processing flow with cache
- E2E Tests: Playwright tests uploading CSV and downloading results
- Performance Tests: 1,000 address processing time
Use Cases
Business Registration System
Agency processes employee addresses during business registration:
// Get employee addresses from registration form
const employees = formData.getAll("employee_address");
// Bulk geocode all addresses
const results = await geocodeAddressesBulk(employees);
// Store municipality info with each employee record
employees.forEach((employee, i) => {
if (results.data[i]) {
employee.municipality = results.data[i].municipality.name;
employee.formattedAddress = results.data[i].formattedAddress;
}
});
Data Migration
Normalize existing address database:
- Export addresses from legacy system
- Upload CSV to bulk processing page
- Download results with municipality info
- Import into new system
Related Documentation
- Bulk Geocoding Server Action - Processing logic
- Use Cases - Bulk processing business logic
- Bulk Components - UI components
- CSV Parsing - File upload and parsing utilities