php
47 lines · 9 steps
Streaming a large CSV export in Laravel
Export orders to CSV without loading the whole table into memory by streaming rows in chunks.
Explained by
highlit
1<?php
2
3namespace App\Http\Controllers;
4
5use App\Models\Order;
6use Symfony\Component\HttpFoundation\StreamedResponse;
7
8class OrderExportController extends Controller
9{
10 public function export(): StreamedResponse
11 {
12 $headers = [
13 'Content-Type' => 'text/csv; charset=UTF-8',
14 'Content-Disposition' => 'attachment; filename="orders.csv"',
15 'X-Accel-Buffering' => 'no',
16 'Cache-Control' => 'no-store, no-cache',
17 ];
18
19 $columns = ['id', 'reference', 'customer_email', 'total_cents', 'status', 'placed_at'];
20
21 return response()->stream(function () use ($columns) {
22 $out = fopen('php://output', 'w');
23 fputcsv($out, $columns);
24
25 Order::query()
26 ->select($columns)
27 ->where('status', '!=', 'draft')
28 ->orderBy('id')
29 ->chunkById(2000, function ($orders) use ($out, $columns) {
30 foreach ($orders as $order) {
31 fputcsv($out, [
32 $order->id,
33 $order->reference,
34 $order->customer_email,
35 number_format($order->total_cents / 100, 2, '.', ''),
36 $order->status,
37 $order->placed_at?->toIso8601String(),
38 ]);
39 }
40
41 flush();
42 });
43
44 fclose($out);
45 }, 200, $headers);
46 }
47}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Streaming responses let you send data to the client as it's generated instead of buffering the entire payload in memory.
- 2chunkById paginates by primary key so a huge result set is processed in bounded batches rather than all at once.
- 3Disabling proxy and browser buffering plus calling flush ensures rows actually reach the client during generation.
Related explainers
php
<?php namespace App\Http\Controllers\Auth;
Rate-limited login in Laravel
authentication
rate-limiting
validation
Intermediate
9 steps
php
public function importUsers(array $users): int { $inserted = 0;
Bulk-inserting users with batched PDO upserts
batching
bulk-insert
prepared-statements
Intermediate
6 steps
php
<?php namespace App\Events;
A priority event dispatcher in PHP
observer-pattern
callbacks
priority-ordering
Intermediate
8 steps
php
<?php namespace App\Http\Controllers;
Verifying Stripe webhooks in Laravel
webhooks
signature-verification
event-dispatch
Intermediate
8 steps
typescript
interface Page<T> { items: T[]; nextCursor: string | null; }
Streaming cursor pagination with async generators
async-generators
pagination
generics
Intermediate
8 steps
php
<?php namespace App\Http\Controllers;
Building a filtered product index in Laravel
query-builder
validation
conditional-queries
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/streaming-a-large-csv-export-in-laravel-explained-php-4e2d/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.