Vivek Mistry 👋

I’m a Certified Senior Laravel Developer with 8+ years of experience , specializing in building robust APIs and admin panels, frontend templates converting them into fully functional web applications.

Book A Call
  • 24 Dec, 2025
  • 717 Views
  • Both save memory, but they solve different problems. Picking the wrong one can hurt performance.

cursor() vs lazy() in Laravel — Choose the Right One for Large Datasets

🚀 The Common Scenario

At some point, every Laravel app needs to process thousands or millions of records:

  • exporting users
  • syncing data
  • sending notifications
  • running background jobs
  • fixing legacy data

Loading everything into memory with get() is dangerous.

Laravel gives us two memory-friendly tools:

  • cursor()
  • lazy()

They look similar — but they are not interchangeable.

🎯 What cursor() Really Does

foreach (User::cursor() as $user) {
    // process user
}

✔ How it works:

  • Uses one single database query
  • Fetches one row at a time
  • Uses a PHP generator
  • Extremely low memory usage

⚠️ Important limitation:

  • Keeps one DB connection open
  • No chunking
  • Slow for very large datasets
  • Can timeout on long-running jobs

🎯 What lazy() Really Does

foreach (User::lazy() as $user) {
    // process user
}

✔ How it works:

  • Executes multiple chunked queries
  • Loads records in small batches
  • Releases DB connection between chunks
  • Safer for long-running jobs

✔ Default chunk size:

User::lazy(1000);

🧠 Real-World Examples

✔ Example 1: Sending Emails (Best → lazy())

User::where('active', true)
    ->lazy(500)
    ->each(fn ($user) => sendEmail($user));

Why lazy()?

  • Long-running job
  • Safe chunking
  • No DB connection lock

✔ Example 2: Streaming Data to CSV (Best → cursor())

$handle = fopen('php://output', 'w');

foreach (Order::cursor() as $order) {
    fputcsv($handle, [$order->id, $order->total]);
}

Why cursor()?

  • One row at a time
  • Minimal memory
  • No need to store batches

✔ Example 3: Data Fix Script (Best → lazy())

Product::whereNull('slug')
    ->lazy()
    ->each(fn ($product) => $product->update([
        'slug' => Str::slug($product->name)
    ]));

Safer than cursor() because:

  • Updates take time
  • Avoids DB connection timeout

⚠️ Common Mistake Developers Make

❌ Using cursor() for everything:

foreach (User::cursor() as $user) {
    sleep(1); // BAD
}

This keeps the DB connection open for minutes — risky in production.

🧩 Simple Rule to Remember

Use cursor() for fast, read-only, streaming operations.
Use lazy() for long-running or write operations.

🏁 Final Thought

Both cursor() and lazy() solve memory issues —

but choosing the wrong one creates performance problems.

  • cursor() → ultra-low memory, fast reads
  • lazy() → safer, chunked, production-friendly

Understanding this difference puts you ahead of most Laravel developers.

Share: