Next.js template
Asynchronous file processing, ready to run
A working Next.js example that stores CSV uploads, sends processing jobs to RocketStack Queue, and runs the work asynchronously in a Function.
Architecture
Source path: examples/nextjs-file-processing
What the template includes
Next.js upload route
App Router handler at POST /api/uploads with multipart validation.
File validation
Server-side CSV type, size, and path-sanitization checks.
RocketStack Object Storage integration
Stores the original CSV before queueing background work.
RocketStack Queue integration
Enqueues concise job metadata — never the file contents.
CSV-processing Function
Downloads, parses, and summarizes the stored CSV asynchronously.
Sample CSV and setup guide
Bundled fictional customers.csv plus README and console inspection steps.
Architecture
Browser | v Next.js upload route | v RocketStack Object Storage | v RocketStack Queue | v RocketStack Function | v Processing result
Interactive sample preview
Sample CSV
| customer_id | company | plan | signup_date |
|---|---|---|---|
| CUST-1001 | Northwind Analytics | starter | 2025-01-14 |
| CUST-1002 | Blue Harbor Labs | growth | 2025-02-03 |
| CUST-1003 | Summit Field Co | starter | 2025-02-18 |
| CUST-1004 | Orbit Metrics | growth | 2025-03-02 |
| CUST-1005 | Harborline Systems | enterprise | 2025-03-21 |
| CUST-1006 | Clearpath Studio | starter | 2025-04-05 |
Example result
Illustrative summary after Function processing.
- Rows
- 12
- Columns
- 4
- Invalid rows
- 0
Key code excerpts
Validate and upload the file
export async function POST(request: Request) {
const formData = await request.formData()
const entry = formData.get('file')
if (!(entry instanceof File)) {
return Response.json({ error: 'Missing file field' }, { status: 400 })
}
const validation = validateUploadFile(entry)
if (!validation.ok) {
const status = validation.code === 'too_large' ? 413 : 400
return Response.json({ error: validation.message }, { status })
}
const jobId = createJobId()
const objectPath = buildObjectPath(jobId, validation.fileName, getStoragePrefix())
await uploadObject(entry, objectPath)
await enqueueFileProcessingJob({
jobId,
type: 'csv.import',
objectPath,
originalFileName: validation.fileName,
contentType: validation.contentType
})
return Response.json({ jobId, status: 'queued', fileName: validation.fileName }, { status: 202 })
}Add the processing job to Queue
export async function enqueueFileProcessingJob(
payload: FileProcessingJob
): Promise<void> {
const queueId = requiredEnv('ROCKETSTACK_QUEUE_ID')
const queues = getQueuesClient()
const response = await queues.enqueueMessage(queueId, {
payload,
idempotencyKey: payload.jobId
})
if (!response.data?.data?.messageId) {
throw new Error('Queue enqueue returned an unexpected response')
}
}Process the stored CSV
exports.handler = async function handler(event) {
const payload = event?.payload
if (!payload?.jobId || !payload?.objectPath || payload?.type !== 'csv.import') {
throw new Error('Invalid queue delivery payload')
}
const summaryPath = resultPath(payload.jobId)
if (await objectExists(summaryPath)) {
return { success: true, jobId: payload.jobId, skipped: true }
}
await updateJobStatus(payload.jobId, 'processing')
const csvText = await fetchObjectText(payload.objectPath)
const parsed = parseCsv(csvText)
const summary = {
success: true,
jobId: payload.jobId,
objectPath: payload.objectPath,
rowCount: parsed.rowCount,
columnCount: parsed.columnCount,
columns: parsed.columns,
invalidRowCount: parsed.invalidRowCount,
processedAt: new Date().toISOString()
}
await uploadTextObject(summaryPath, JSON.stringify(summary), 'application/json')
await updateJobStatus(payload.jobId, 'completed', { summary })
return summary
}Setup steps
Open the READMEStep 1
Clone the example
Copy examples/nextjs-file-processing and install dependencies.
Step 2
Add environment variables
Set ROCKETSTACK_API_KEY and ROCKETSTACK_QUEUE_ID in .env.local.
Step 3
Create Storage, Queue, and Function
Deploy process-csv and point the Queue delivery target at it.
Step 4
Upload the sample CSV
Use the bundled customers.csv or another safe CSV to exercise the pipeline.
Full install, upload, and troubleshooting steps are in examples/nextjs-file-processing/README.md.
Retry and duplicate-processing guidance
Deterministic result path
The Function writes results/{jobId}/summary.json and skips work when that object already exists.
KV job status
Job status is stored at file-job:{jobId} in RocketStack KV. Updates are best-effort and not atomic exactly-once claims.
Application database
For irreversible side effects, persist completed job IDs in your own database before applying business logic.
Production considerations
- Keep RocketStack API keys server-side only
- Validate file type and size before upload
- Sanitize object paths and reject traversal patterns
- Queue only job metadata — never file contents
- Limit parser memory usage with row and column caps
- Monitor failed deliveries and dead-lettered messages in the console
- Review Free plan usage limits before going live
Object Storage documentation · Queue documentation · Functions documentation · Pricing
Related workflows
File workflows
Asynchronous file processing
Store uploads immediately, then process documents, images, CSVs, or AI tasks asynchronously.
Incoming events
Reliable webhook processing
Acknowledge webhooks immediately, then process each event safely in the background.
Run the template with RocketStack
Create a free account, get an API key, and connect Object Storage, Queue, and Function resources used by the example.
