How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: How to Do a Left Outer Join in Laravel Query Builder
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Learn > Web Development > How to Do a Left Outer Join in Laravel Query Builder
Web Development

How to Do a Left Outer Join in Laravel Query Builder

how7o
By how7o
Last updated: April 20, 2026
8 Min Read
Laravel left outer join — query builder leftJoin illustration with two tables
SHARE

A laravel left outer join — every row from the left table, optional match on the right, NULL where there’s no match — is the right tool whenever the right-hand relationship is optional: users with or without profiles, products with or without reviews, orders with or without refunds. Laravel’s query builder exposes it as leftJoin(), and this guide shows the four-argument shorthand, a full working example, the closure form for multiple conditions, leftJoinSub for joining subqueries, and when to skip joins entirely in favor of Eloquent’s with().

Contents
  • TL;DR
  • Basic syntax
  • A full working example
  • join vs leftJoin: the set behavior
  • Multiple conditions via closure
  • Joining a subquery: leftJoinSub
  • When to use Eloquent with() instead
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-04-21 on Laravel 11 with PHP 8.3 and MySQL 8.0. Originally published 2023-10-10, rewritten and updated 2026-04-21.

TL;DR

Chain ->leftJoin('right_table', 'left_table.id', '=', 'right_table.left_id') onto the query builder. join is an inner join; leftJoin keeps every row from the left side and fills the right-side columns with NULL when nothing matches. For multiple join conditions, pass a closure. For subqueries, use leftJoinSub.

Basic syntax

The core method call you’ll use 90% of the time:

->leftJoin('right_table', 'left_table.id', '=', 'right_table.left_id')

Four positional arguments: the right-hand table, the left-side column, the comparison operator (almost always '='), and the right-side foreign-key column. The method returns the same query builder so you can chain further where, select, or orderBy calls.

A full working example

Say you have a users table and an optional profiles table keyed by user_id. You want every user plus their profile bio where one exists, NULL otherwise:

use Illuminate\Support\Facades\DB;

$rows = DB::table('users')
    ->select('users.id', 'users.name', 'users.email', 'profiles.bio')
    ->leftJoin('profiles', 'users.id', '=', 'profiles.user_id')
    ->orderBy('users.id')
    ->get();

The generated SQL is:

SELECT users.id, users.name, users.email, profiles.bio
FROM users
LEFT JOIN profiles ON users.id = profiles.user_id
ORDER BY users.id ASC

Users without a profile row still appear in the result; profiles.bio is null for them. Swap DB::table('users') for User::query() if you want an Eloquent model query — the join API is identical.

laravel left outer join — Venn diagram of left join versus inner join

join vs leftJoin: the set behavior

Same table layout, different join call — different result:

// Inner join: only users who HAVE a profile
DB::table('users')
    ->join('profiles', 'users.id', '=', 'profiles.user_id')
    ->get();

// Left outer join: ALL users, profile columns NULL if no profile
DB::table('users')
    ->leftJoin('profiles', 'users.id', '=', 'profiles.user_id')
    ->get();

Picking the wrong one is the most common join bug: if you see “users mysteriously disappearing from the report,” chances are an inner join is silently dropping rows because they have no matching right-side record.

Multiple conditions via closure

When the join condition is more than a single column equality — say, only join paid orders — pass a closure instead of the four-arg shorthand:

DB::table('users')
    ->leftJoin('orders', function ($join) {
        $join->on('users.id', '=', 'orders.user_id')
             ->where('orders.status', '=', 'paid');
    })
    ->select('users.id', 'users.name', 'orders.total')
    ->get();

Inside the closure you have the full join grammar: on, orOn, where, whereIn, whereNull, and so on. Anything that belongs in the ON clause goes here — don’t move these conditions to the outer where, because that converts a left join into an inner join at the semantic level (filtering NULL right-side rows back out).

Joining a subquery: leftJoinSub

Sometimes the right side isn’t a table but a derived result set — say, each user’s most recent post. Build the subquery separately and pass it to leftJoinSub:

$latestPost = DB::table('posts')
    ->selectRaw('user_id, MAX(created_at) as last_post')
    ->groupBy('user_id');

$rows = DB::table('users')
    ->leftJoinSub($latestPost, 'p', 'users.id', '=', 'p.user_id')
    ->select('users.id', 'users.name', 'p.last_post')
    ->get();

The second argument ('p') is the alias used everywhere else in the outer query. The remaining three positional arguments are the same first-column / operator / second-column triplet as leftJoin.

When to use Eloquent with() instead

If you’re working with Eloquent models and relationships, a raw join is often the wrong tool. User::with('profile')->get() runs two queries — one for users, one for their profiles — and hydrates them as related models. You get full Eloquent features: mutators, casts, relationship methods on the loaded objects.

// With a hasOne / hasMany relationship defined on User:
$users = User::with('profile')->get();

foreach ($users as $user) {
    echo $user->name.': '.($user->profile?->bio ?? 'no bio').PHP_EOL;
}

Rule of thumb: use with() for object-oriented application code, use leftJoin when you need a single flat rowset (reports, exports, CSV dumps) or when you need to filter on right-side columns in ways Eloquent relationships can’t express efficiently.

Frequently asked questions

What’s the basic laravel left outer join syntax?

Chain ->leftJoin('right_table', 'left_table.id', '=', 'right_table.left_id') onto a query builder. The four arguments are: the right table, the left-side column, the operator ('=' for equi-joins), and the right-side column. The method is on the query builder, so start from DB::table('left_table') or Model::query().

How is leftJoin different from join?

join performs an inner join: rows are returned only where a match exists in both tables. leftJoin returns every row from the left table and fills the right-side columns with NULL when no match is found. Use leftJoin when you want “users and their optional profiles” — users without a profile row still appear.

Can I join on multiple conditions?

Yes. Pass a closure instead of the four-argument shorthand: ->leftJoin('orders', function ($j) { $j->on('users.id', '=', 'orders.user_id')->where('orders.status', 'paid'); }). Anything you can do inside a WHERE you can do inside the join condition, including orOn and whereIn.

What about joining a subquery?

Use leftJoinSub. Build the subquery with the query builder, give it an alias, then pair it with the join condition: $latest = DB::table('posts')->selectRaw('user_id, MAX(created_at) as last_post')->groupBy('user_id'); DB::table('users')->leftJoinSub($latest, 'p', 'users.id', '=', 'p.user_id')->get();

When should I use Eloquent with() instead of a raw join?

Use with() when you’re working with Eloquent models and relationships — User::with('posts')->get() is cleaner, eager-loads in a separate query, and gives you full model hydration. Reach for leftJoin when you need the database to produce a single flat result set (reports, exports, aggregates) or when you need columns from the right table in WHERE / ORDER BY clauses the relationship can’t express.

Related guides

  • How to Install Laravel on Ubuntu — set up Laravel 11 before building queries.
  • How to Add Foreign Keys in Laravel Migration — design the relationships your joins rely on.
  • Laravel Eloquent where / orWhere — filter the joined result set.
  • Laravel Eloquent group by + count — aggregate across joined rows.

References

Official Laravel query builder docs (joins, leftJoin, leftJoinSub): laravel.com/docs/queries. Eloquent eager-loading with with(): laravel.com/docs/eloquent.

TAGGED:EloquentLaravelmysqlphpsql

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Laravel last inserted ID — Eloquent save populates model primary key illustration How to Retrieve the Last Inserted ID in Laravel Eloquent
Next Article Laravel rollback specific migration — Artisan migrate:rollback --path command illustration How to Rollback a Specific Migration in Laravel
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow
Most Popular
Display PHP errors — ini_set + php.ini configuration
How to Display PHP Errors
May 10, 2026
PHP convert string to uppercase — strtoupper and mb_strtoupper
How to Convert a String to Uppercase in PHP
May 10, 2026
PHP string to float conversion with cast, regex cleanup, NumberFormatter
How to Convert a String to Float in PHP
May 10, 2026
PHP merge arrays without duplicates — union operator and array_unique
How to Combine Two Arrays Without Duplicates in PHP
May 10, 2026
PHP delete array element — unset, array_splice, array_filter, array_search
How to Delete an Element from a PHP Array
May 10, 2026

You Might Also Like

MySQL top CPU usage — PROCESSLIST snapshot and performance_schema digest
Server Management

How to Check Which MySQL Database or User Is Using the Most CPU

8 Min Read
WooCommerce homepage filter to hide out of stock products
Web Development

Hide Out of Stock Products from Homepage in WooCommerce (Keep Them Visible Elsewhere)

5 Min Read
WooCommerce add custom fee — woocommerce_cart_calculate_fees + WC()->cart->add_fee
Web Development

How to Add a Custom Fee (or Transaction Fee) in WooCommerce

8 Min Read
Laravel DataTables HTML column — rawColumns opt-out of the default escaping
Web Development

How to Add an HTML Column in Laravel DataTables

7 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?