Sr Technical Content Strategist and Team Lead

Laravel Eloquent provides several methods to order query results directly at the database level, giving you full control over how records are sorted before they reach your application code. The orderBy() method is the most common way to add an ORDER BY clause to your Eloquent queries, but Laravel also offers convenience methods like orderByDesc(), latest(), oldest(), and orderByRaw() for different sorting needs.
In a previous part of this series, you learned how to obtain database records using the all() method from within an Eloquent model. You may recall using a method called sortDesc(), which was used to sort the records in descending order.
The sortDesc() method is part of the Collection class, a powerful Laravel utility class that works as an improved version of native PHP arrays. Instead of ordering results within the database query itself, this method inverts the order of a collection so that the last item appears first. While that works well for smaller result sets, it does not offer the same flexibility or performance as sorting the results in the database query itself.
This tutorial walks you through every ordering method available in Laravel Eloquent, from basic orderBy() usage to advanced techniques like raw SQL expressions and dynamic ordering with user input. You will also learn how ordering interacts with pagination and when to use collection-level sorting instead.
orderBy('column', 'direction') to sort Eloquent query results at the database level, which is more efficient than sorting PHP collections after retrieval.latest() and oldest() are convenient shortcuts for ordering by timestamp columns without writing out the full orderBy() call.orderBy() calls to sort by more than one column. Laravel applies the ordering in the sequence you chain them.orderByRaw() with parameter bindings for complex SQL sorting expressions, and never pass unvalidated user input directly.asc or desc.To follow this tutorial, you need:
The ordering methods covered in this tutorial (orderBy, orderByDesc, latest, oldest, orderByRaw) are available in Laravel 8 through the current Laravel 13. The syntax has remained stable across these versions. If you are using an older version, check the Laravel documentation for your specific release.
Before writing ordering queries, it helps to understand the two distinct approaches Laravel offers for sorting data: database-level ordering and collection-level sorting.
Database-level ordering uses the SQL ORDER BY clause. When you call orderBy() on an Eloquent query builder, Laravel appends ORDER BY to the generated SQL statement. The database engine handles the sorting before returning results to PHP, which is efficient because databases are optimized for this operation.
Collection-level sorting happens in PHP after the data has already been fetched from the database. Methods like sortBy() and sortByDesc() operate on Eloquent Collections that are already loaded into memory.
For most use cases, database-level ordering is the better choice because the database can use indexes to speed up sorting. Collection-level sorting is useful when you need to reorder data that is already in memory or when sorting by a computed value that does not exist as a database column.
When no ORDER BY clause is specified, databases do not guarantee any particular order of results. In practice, MySQL and PostgreSQL often return rows in primary key order, but this behavior is not reliable and can change based on query plans, indexes, or storage engine internals. Always specify an explicit order when the sequence of results matters to your application.
The orderBy() method is the primary way to sort query results in Laravel Eloquent. It translates directly to a SQL ORDER BY clause.
Model::orderBy('column_name', 'direction')->get();
The method accepts two arguments:
'asc' for ascending or 'desc' for descending. Defaults to 'asc' if omitted.This generates the following SQL:
SELECT * FROM table_name ORDER BY column_name ASC|DESC;
Ascending order is the default. These two calls produce identical SQL:
// Explicit ascending
$users = User::orderBy('name', 'asc')->get();
// Implicit ascending (same result)
$users = User::orderBy('name')->get();
Both generate:
SELECT * FROM users ORDER BY name ASC;
To sort from highest to lowest (or newest to oldest for dates), pass 'desc' as the second argument:
$posts = Post::orderBy('created_at', 'desc')->get();
This generates:
SELECT * FROM posts ORDER BY created_at DESC;
You will now change the code in your routes/web.php file to show results ordered from newest to oldest, based on the created_at table field.
Both the created_at and the updated_at fields are managed by Eloquent when you include a timestamps() definition in your table migration. You should not update these fields manually, but you can use them to sort and filter your queries.
Open this file in your code editor:
- routes/web.php
This is how the code looks now:
<?php
use Illuminate\Support\Facades\Route;
use App\Models\Link;
use App\Models\LinkList;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
$links = Link::all()->sortDesc();
return view('index', [
'links' => $links,
'lists' => LinkList::all()
]);
});
Route::get('/{slug}', function ($slug) {
$list = LinkList::where('slug', $slug)->first();
if (!$list) {
abort(404);
}
return view('index', [
'list' => $list,
'links' => $list->links,
'lists' => LinkList::all()
]);
})->name('link-list');
Notice that the /{slug} route, which is responsible for listing the links by slug, currently does not use any sorting method. Links are obtained through the list variable, highlighted in the code, using the relationship defined in the LinkList model.
If you add multiple links to a list now, the query will return results ordered from oldest to newest by default. Although you could use the sortDesc() method to reorder the collection within the $list->links call, using the orderBy() method provides more flexibility and allows you to include additional filtering conditions later. You can chain this method with a where() call for even more fine-grained results.
Replace the highlighted line in the previous code sample with the following line:
'links' => $list->links()->orderBy('created_at', 'desc')->get(),
Notice that this time we are invoking the built-in query builder by calling the $list->links() method, which refers to the relationship method defined in the LinkList class. This is different from calling $list->links as a class property (without the parenthesis), which will invoke a magic method in the model to fetch all links related to that list.
This is how the full routes/web.php file should look once you are finished:
<?php
use Illuminate\Support\Facades\Route;
use App\Models\Link;
use App\Models\LinkList;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
$links = Link::all()->sortDesc();
return view('index', [
'links' => $links,
'lists' => LinkList::all()
]);
});
Route::get('/{slug}', function ($slug) {
$list = LinkList::where('slug', $slug)->first();
if (!$list) {
abort(404);
}
return view('index', [
'list' => $list,
'links' => $list->links()->orderBy('created_at', 'desc')->get(),
'lists' => LinkList::all()
]);
})->name('link-list');
Save and close the file. Now, add a couple new links using the link:new Artisan command. You can use the default list:
- docker-compose exec app php artisan link:new
Output Link URL:
> https://laravel.com/docs/13.x/eloquent
Link Description:
> Laravel Eloquent Docs
Link List (leave blank to use default):
>
New Link:
https://laravel.com/docs/13.x/eloquent - Laravel Eloquent Docs
Listed in: default
Is this information correct? (yes/no) [no]:
> yes
Saved.
If you reload the default link list page, you should now obtain links from newest to oldest:
http://localhost:8000/default

Likewise, if you would prefer to order links alphabetically by the link description, you would have to change the line to use that table field in the method call like this:
'links' => $list->links()->orderBy('description', 'asc')->get(),
This is how the links would be ordered after such change:

The orderByDesc() method is a convenience wrapper around orderBy('column', 'desc'). It accepts a single argument: the column name.
Use orderByDesc() when you want descending order and prefer a shorter, more readable method call. The two approaches generate identical SQL:
// Using orderBy with desc direction
$posts = Post::orderBy('published_at', 'desc')->get();
// Using orderByDesc (same SQL output)
$posts = Post::orderByDesc('published_at')->get();
Both produce:
SELECT * FROM posts ORDER BY published_at DESC;
Here is a practical example that fetches the five most recently updated products:
$recentProducts = Product::orderByDesc('updated_at')
->limit(5)
->get();
The generated SQL:
SELECT * FROM products ORDER BY updated_at DESC LIMIT 5;
Laravel provides latest() and oldest() as shorthand methods for ordering by timestamp columns. These are especially useful because ordering by created_at is one of the most common operations in web applications.
The latest() method is a shortcut for orderBy('created_at', 'desc'):
// These two queries produce identical SQL
$posts = Post::latest()->get();
$posts = Post::orderBy('created_at', 'desc')->get();
Both generate:
SELECT * FROM posts ORDER BY created_at DESC;
The oldest() method is the inverse, equivalent to orderBy('created_at', 'asc'):
$posts = Post::oldest()->get();
Generates:
SELECT * FROM posts ORDER BY created_at ASC;
Both methods accept an optional column name argument if you want to order by a timestamp column other than created_at:
// Order by the most recently updated posts
$posts = Post::latest('updated_at')->get();
// Order by the earliest published posts
$posts = Post::oldest('published_at')->get();
These generate:
SELECT * FROM posts ORDER BY updated_at DESC;
SELECT * FROM posts ORDER BY published_at ASC;
In many applications, you need to sort by more than one column. For example, sorting users by last name and then by first name for users who share the same last name.
To order by multiple columns, chain orderBy() calls:
$users = User::orderBy('last_name', 'asc')
->orderBy('first_name', 'asc')
->get();
This generates:
SELECT * FROM users ORDER BY last_name ASC, first_name ASC;
Laravel applies the ordering in the sequence you chain the methods. In the example above, the database first sorts by last_name. When multiple rows have the same last_name, the database then sorts those rows by first_name.
You can mix directions when chaining:
$orders = Order::orderBy('status', 'asc')
->orderByDesc('created_at')
->get();
This generates:
SELECT * FROM orders ORDER BY status ASC, created_at DESC;
The orderByRaw() method lets you pass a raw SQL expression as the ORDER BY clause. This is useful when you need to sort by a computed value, a conditional expression, or a database function that Eloquent does not wrap natively.
Model::orderByRaw('raw SQL expression')->get();
Common use cases include:
FIELD(), CASE WHEN)When your raw expression includes values, always pass them as bindings through the second parameter. This prevents SQL injection:
$tasks = Task::orderByRaw('FIELD(status, ?, ?, ?)', ['urgent', 'active', 'closed'])
->get();
This generates a parameterized query:
SELECT * FROM tasks ORDER BY FIELD(status, 'urgent', 'active', 'closed');
The FIELD() function (available in MySQL) returns the position of the first argument in the subsequent list, which lets you define a custom sort order.
Warning: Never pass user-supplied column names or direction values directly into orderByRaw(). Always validate and sanitize any external input before including it in raw SQL expressions. Use the dynamic ordering approach described later in this tutorial for handling user input safely.
Sort orders by the time difference between when they were last updated and when they were created:
$orders = Order::orderByRaw('updated_at - created_at DESC')->get();
This generates:
SELECT * FROM orders ORDER BY updated_at - created_at DESC;
The updated_at - created_at syntax works in MySQL and PostgreSQL. If you are using SQL Server, you would need DATEDIFF(second, created_at, updated_at) instead.
Sometimes you need to sort data that is already loaded in memory. Laravel’s Collection class provides sortBy() and sortByDesc() for this purpose.
Collection-level sorting makes sense when:
For large datasets, database-level ordering with orderBy() is significantly faster because:
As a general rule, use orderBy() at the query level whenever possible. Reserve collection sorting for small datasets or situations where the sort criteria cannot be expressed in SQL.
You can pass a callback to sortBy() for custom sorting logic:
$links = Link::all();
// Sort by the length of the description
$sorted = $links->sortBy(function ($link) {
return strlen($link->description);
});
// Sort by a related model's attribute
$sorted = $links->sortBy(function ($link) {
return $link->link_list->title;
});
The sortByDesc() method works the same way but in reverse order:
$sorted = $links->sortByDesc('created_at');
Collection sorting returns a new collection and does not modify the original. The sort methods also preserve array keys. If you need re-indexed keys, chain ->values() after sorting.
In many applications, users expect to sort tables or lists by clicking column headers. Implementing this requires accepting the column name and sort direction from the HTTP request, but you must validate these inputs to prevent SQL injection and unexpected errors.
Never pass a user-supplied column name directly to orderBy(). Instead, check it against an explicit list of allowed columns:
$allowedColumns = ['name', 'email', 'created_at', 'updated_at'];
$sortColumn = in_array($request->input('sort'), $allowedColumns)
? $request->input('sort')
: 'created_at';
Restrict the direction value to only asc or desc:
$sortDirection = $request->input('direction') === 'asc' ? 'asc' : 'desc';
Here is a complete route example that handles dynamic ordering safely:
Route::get('/users', function (Illuminate\Http\Request $request) {
$allowedColumns = ['name', 'email', 'created_at'];
$allowedDirections = ['asc', 'desc'];
$sortColumn = in_array($request->input('sort'), $allowedColumns)
? $request->input('sort')
: 'created_at';
$sortDirection = in_array($request->input('direction'), $allowedDirections)
? $request->input('direction')
: 'desc';
$users = User::orderBy($sortColumn, $sortDirection)->paginate(20);
return view('users.index', ['users' => $users]);
});
A request to /users?sort=name&direction=asc generates:
SELECT * FROM users ORDER BY name ASC LIMIT 20 OFFSET 0;
Ordering and pagination work together naturally in Laravel. When you chain orderBy() before paginate(), Laravel preserves the sort order across all pages of results.
Laravel’s paginate() and simplePaginate() methods automatically append the ORDER BY clause to every paginated query. The pagination links generated by these methods include the necessary query parameters to maintain the current page context.
Route::get('/posts', function () {
$posts = Post::orderBy('created_at', 'desc')->paginate(15);
return view('posts.index', ['posts' => $posts]);
});
This generates a query like:
SELECT * FROM posts ORDER BY created_at DESC LIMIT 15 OFFSET 0;
On subsequent pages, the offset changes while the ordering remains consistent:
SELECT * FROM posts ORDER BY created_at DESC LIMIT 15 OFFSET 15;
In your Blade template, render the pagination links:
{{ $posts->links() }}
For more details on implementing pagination in Laravel, see the How To Limit and Paginate Query Results in Laravel Eloquent tutorial.
The following table summarizes all ordering methods available in Laravel Eloquent:
| Method | Default Direction | Typical Use Case | SQL Equivalent |
|---|---|---|---|
orderBy('col', 'asc') |
asc |
General-purpose ascending sort | ORDER BY col ASC |
orderBy('col', 'desc') |
N/A (explicit) | General-purpose descending sort | ORDER BY col DESC |
orderByDesc('col') |
desc |
Shorthand for descending sort | ORDER BY col DESC |
latest() |
desc |
Newest records by created_at |
ORDER BY created_at DESC |
latest('col') |
desc |
Newest records by custom column | ORDER BY col DESC |
oldest() |
asc |
Oldest records by created_at |
ORDER BY created_at ASC |
oldest('col') |
asc |
Oldest records by custom column | ORDER BY col ASC |
orderByRaw('expr') |
N/A (raw) | Complex or computed expressions | ORDER BY expr |
reorder() |
N/A | Remove all existing ordering | Removes ORDER BY clause |
reorder('col', 'dir') |
N/A | Replace existing ordering | Replaces ORDER BY clause |
Collection-level methods (operate on data already in PHP memory):
| Method | Direction | Typical Use Case |
|---|---|---|
sortBy('col') |
Ascending | Re-sort a loaded collection |
sortByDesc('col') |
Descending | Re-sort a loaded collection in reverse |
sortBy(callback) |
Ascending | Sort by computed or nested value |
Use the orderBy('column', 'direction') method before calling get() or paginate(). The direction parameter accepts 'asc' for ascending or 'desc' for descending, and defaults to 'asc' if omitted:
$users = User::orderBy('name', 'asc')->get();
This appends ORDER BY name ASC to the generated SQL query.
orderBy() on a query and sortBy() on a Collection?orderBy() adds an ORDER BY clause to the SQL query and runs at the database level. sortBy() is called on a PHP Collection object after the data has already been fetched. For large datasets, orderBy() is more efficient because the database engine handles sorting using indexes. sortBy() is best for small datasets or when you need to re-sort data that is already in memory.
Chain multiple orderBy() calls. Laravel applies the ordering in the sequence the methods are chained:
$users = User::orderBy('last_name', 'asc')
->orderBy('first_name', 'asc')
->get();
This produces ORDER BY last_name ASC, first_name ASC in the generated SQL. The database first sorts by last_name, then by first_name for rows where last_name is identical.
orderByRaw() safe to use with user input?Not directly. Never pass user-supplied column names or direction values into orderByRaw() without validation. For expressions that require value bindings, use the second parameter to pass bindings safely:
Task::orderByRaw('FIELD(status, ?, ?)', ['active', 'inactive'])->get();
For user-controlled column names and directions, use orderBy() with an allowlist as described in the Dynamic Ordering section of this tutorial.
latest() and oldest() do in Laravel Eloquent?latest() is shorthand for orderBy('created_at', 'desc') and returns the most recent records first. oldest() is shorthand for orderBy('created_at', 'asc') and returns the earliest records first. Both methods accept an optional column name argument if you need to order by a timestamp column other than created_at:
Post::latest('published_at')->get();
In this tutorial, you learned how to order query results in Laravel Eloquent using orderBy(), orderByDesc(), latest(), oldest(), and orderByRaw(). You also explored how to sort by multiple columns, handle dynamic user input safely, combine ordering with pagination, and choose between database-level ordering and collection-level sorting.
The key principle to keep in mind: sort at the database level with orderBy() whenever possible, and reserve collection-level sorting with sortBy() for small datasets or computed values that cannot be expressed in SQL.
In the next part of this series, you will learn how to get the total result count from a Laravel Eloquent query.
If you want to keep building on these concepts, explore the following DigitalOcean resources:
You can also deploy your Laravel application on DigitalOcean App Platform, which provides a fully managed infrastructure for PHP applications with built-in support for managed databases. If you need a dedicated database, DigitalOcean Managed Databases offers MySQL and PostgreSQL clusters with automated backups and scaling.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Eloquent is an object relational mapper (ORM) that is included by default within the Laravel framework. In this project-based series, you’ll learn how to make database queries and how to work with relationships in Laravel Eloquent. To follow along with the examples demonstrated throughout the series, you’ll improve a demo application with new models and relationships. Visit the series introduction page for detailed instructions on how to download and set up the project.
I help Businesses scale with AI x SEO x (authentic) Content that revives traffic and keeps leads flowing | 3,000,000+ Average monthly readers on Medium | Sr Technical Writer(Team Lead) @ DigitalOcean | Ex-Cloud Consultant @ AMEX | Ex-Site Reliability Engineer(DevOps)@Nutanix
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.