Laravel pagination is essential for high-performance apps. Learn how to use Eloquent pagination to manage large datasets and keep your database queries fast.
Last week, a junior developer on my team pushed a change that tried to load 15,000 user records into a single Blade view. The server memory limit hit a wall, the page took roughly 4 seconds to respond, and the browser eventually crashed. It was a classic "I forgot about scale" moment that we’ve all dealt with at some point.
If you’re building anything more than a toy project, you cannot load every row from your laravel database into memory. That’s where Laravel’s built-in pagination tools come in. They aren’t just a convenience; they’re a requirement for professional web development.
When you use User::all(), you’re telling PHP to fetch every single record from the database and hydrate them into Eloquent models. If you have 50,000 users, you’re going to run out of RAM fast.
Instead, you should use paginate(). This method automatically handles the LIMIT and OFFSET clauses in your SQL queries based on the current page request. It also calculates the total count to generate your navigation links.
Here is the most common way to implement it in a controller:
PHPpublic function index() { #6A9955">// Fetches 15 records per page $users = User::paginate(15); return view('users.index', compact('users')); }
By default, Laravel looks for a ?page= query string in your URL. If it finds one, it slices the data accordingly. It’s clean, it’s fast, and it keeps your server memory usage predictable.
We’ve all had those moments where we thought we needed "Previous" and "Next" buttons, but realized we actually needed the full page number list. Laravel gives you two primary ways to handle this.
If you only need "Next" and "Previous" links, use simplePaginate(). This is faster on massive tables because Laravel doesn't have to run a SELECT COUNT(*) query to figure out how many total pages exist. It just checks if there’s a "next" set of records.
PHP#6A9955">// Use this for huge tables where total count doesn't matter $users = User::simplePaginate(15);
I once worked on an audit log table with around 2 million rows. Switching from paginate() to simplePaginate() shaved about 280ms off the query execution time because the database didn't have to scan the entire index to count rows.
Once you have your paginated collection in your view, displaying the navigation is trivial. You just need to call the links() method on the collection inside your Blade template.
BLADE<div class="user-list"> @foreach ($users as $user) <p>{{ $user->name }}</p> @endforeach </div> {{ $users->links() }}
If you’re using Tailwind CSS, Laravel’s Laravel Blade Templates: Mastering Inheritance and Sections integration will automatically style these for you. If you’re using Bootstrap, you can publish the pagination views using php artisan vendor:publish --tag=laravel-pagination and switch the default driver in your AppServiceProvider.
I’ve seen developers try to "fix" pagination issues by manually slicing arrays. Don't do that. When you use Eloquent pagination, Laravel handles the complex logic of maintaining your query constraints across pages.
One common mistake is forgetting to append query parameters. If your users are filtering by "status" or "search term," those parameters will disappear when they click page 2. Fix it like this:
BLADE{{ $users->appends(['status' => 'active'])->links() }}
Alternatively, if you want to keep all current query string parameters, use:
BLADE{{ $users->withQueryString()->links() }}
Sometimes, standard pagination isn't the right UX. If you're building a social media feed, users hate clicking page numbers. That’s usually where "Infinite Scroll" comes in.
Infinite scroll still uses pagination under the hood, but you return JSON instead of a rendered Blade view, and your JavaScript fetches the next page as the user hits the bottom of the viewport. It’s a bit more work, but it’s a better experience for certain types of web development.
1. Can I change the number of items per page dynamically?
Yes. You can pass a variable to paginate() instead of a hardcoded integer: User::paginate(request('per_page', 15)). Just be sure to validate that input so users don't try to request 1,000,000 items at once.
2. Why is my pagination slow?
If paginate() is slow, it’s usually because of a missing database index on the column you’re sorting by. Check your ORDER BY clause. If you're sorting by created_at, make sure that column is indexed.
3. Does this work with query builders?
Absolutely. paginate() works on both Eloquent models and the Query Builder.
I’m still a fan of keeping things as simple as possible. Before you jump into custom pagination logic or complex infinite scroll implementations, exhaust what the framework gives you out of the box. You’ll save hours of debugging, and your users will get a much snappier experience.
Laravel database transactions are vital for keeping your app consistent. Learn how to use the DB facade to ensure atomic operations and protect data integrity.