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 > Free Laravel, PHP, WordPress & Server Tutorials > 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
Bun runtime — faster JS toolkit replacing npm in Laravel projects
How to Install Bun Runtime on Ubuntu (And Use It in a Laravel Project)
May 24, 2026
Tailscale mesh — peer-to-peer connections between devices, coordination server
How to Install Tailscale on Ubuntu (Zero-Config Mesh VPN for Self-Hosters)
May 24, 2026
Caddy server — automatic HTTPS, 3-line Caddyfile vs 25-line nginx config
How to Install Caddy Server on Ubuntu (Automatic HTTPS, Drop-in nginx Alternative)
May 24, 2026
Cloudflare Tunnel — outbound-only connection from server, no inbound port forward
How to Install Cloudflare Tunnel on Ubuntu (Expose Local Services, No Port Forwarding)
May 24, 2026
WireGuard encrypted tunnel between server and clients with lock icons
How to Set Up WireGuard VPN on Ubuntu (Server, Linux Client, and iOS)
May 24, 2026

You Might Also Like

WordPress cron job without a plugin — cron_schedules, wp_schedule_event, and action callback
Web Development

How to Schedule a Cron Job in WordPress Without a Plugin

7 Min Read
Keep only the digits in a JavaScript string with regex
Web Development

How to Keep Only Numbers in a String with JavaScript

4 Min Read
Laravel login and registration system with scaffolding packages
Web Development

How to Create a Login and Registration System in Laravel

5 Min Read
Keep the first N characters of a JavaScript string with slice
Web Development

How to Keep Only the First N Characters of a String in JavaScript

4 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?