Pulling laravel eloquent records today — rows whose created_at falls within the current calendar day — is a single whereDate call once you know the shape. This guide shows the canonical one-liner, the older-Laravel variant that needs an explicit operator, a Carbon-free alternative using now()->toDateString(), and a high-precision whereBetween form that actually uses your index on large tables.
Last verified: 2026-04-21 on Laravel 11 with PHP 8.3 and MySQL 8.0. Originally published 2022-10-07, rewritten and updated 2026-04-21.
TL;DR
Import Carbon and run Post::whereDate('created_at', Carbon::today())->get(). On older Laravel versions add the explicit operator: whereDate('created_at', '=', Carbon::today()). For large tables, use the index-friendly range form: Post::whereBetween('created_at', [today()->startOfDay(), today()->endOfDay()])->get().
The canonical one-liner
Drop this at the top of the file that uses it:
use Carbon\Carbon;
Then query:
$posts = Post::whereDate('created_at', Carbon::today())->get();
Eloquent’s whereDate scope compiles to DATE(created_at) = ?, and Carbon’s today() returns today’s date at 00:00:00, which Laravel serializes as Y-m-d for the bind. The resulting query returns every row created between today’s midnight and tomorrow’s midnight.
The older-Laravel variant with explicit =
If you’re maintaining a project pinned to an older Laravel minor, you may see a runtime error complaining that whereDate is missing its third argument. The fix is to pass the operator explicitly:
$posts = Post::whereDate('created_at', '=', Carbon::today())->get();
Modern Laravel (8.x and up) accepts the two-argument form and implies =, so the explicit operator is optional — but never wrong. If you’re unsure which minor you’re on, running with the explicit operator is the safe default.

Without a Carbon import: now()->toDateString()
Laravel’s global now() helper returns a Carbon instance, so you can get today’s Y-m-d string without adding a use line:
$posts = Post::whereDate('created_at', now()->toDateString())->get();
now()->toDateString() returns '2026-04-21' (or whatever today is). The scope still compiles to DATE(created_at) = ?; the only difference is cosmetic — one less import line.
High-precision range with whereBetween
whereDate is convenient but wraps created_at in a SQL function, which prevents MySQL from using a B-tree index on that column. On tables with hundreds of thousands of rows, swap to a timestamp range that the optimizer can serve with an index scan:
$posts = Post::whereBetween('created_at', [
today()->startOfDay(),
today()->endOfDay(),
])->get();
today() is a Laravel helper equivalent to Carbon::today(). startOfDay() returns YYYY-MM-DD 00:00:00, endOfDay() returns YYYY-MM-DD 23:59:59, and the resulting SQL is created_at BETWEEN ? AND ? — a plain range predicate that benefits from an index.
Benchmark both on your data before committing; for small tables (<10k rows) the difference is imperceptible and whereDate is more readable.
Timezone watch-outs
“Today” is relative to a timezone. Laravel reads config/app.php‘s timezone and sets PHP’s default accordingly, so Carbon::today() respects the app timezone. MySQL’s TIMESTAMP columns, however, are normalized to UTC under the hood. If app timezone and DB timezone disagree, rows inserted around midnight can appear to “belong” to the wrong day.
Two clean options: keep config/app.php as 'UTC' and convert for display, or pass an explicit zone to Carbon — Carbon::today('Asia/Dhaka')->setTimezone('UTC') — so the bind value matches the stored column’s zone.
Frequently asked questions
Use whereDate against Carbon::today(): Post::whereDate('created_at', Carbon::today())->get(). Laravel compiles the scope to DATE(created_at) = ? and binds today’s Y-m-d string. Remember to use Carbon\Carbon; at the top of the file, or reach for now()->toDateString() instead.
Some Laravel 5.x builds require the explicit operator for whereDate: Post::whereDate('created_at', '=', Carbon::today())->get(). The two-argument form landed later. If you’re on a modern (8.x+) release you can drop the '=' — the error is a signal that you’re on an older minor.
Yes. Laravel’s global now() helper returns a Carbon instance, so Post::whereDate('created_at', now()->toDateString())->get() works with zero explicit imports. Under the hood it’s still Carbon, but you don’t need the use line.
whereDate use my created_at index? Not cleanly. whereDate compiles to DATE(created_at) = ?, which wraps the column in a function and defeats a standard B-tree index on created_at. For high-traffic endpoints, switch to a range: Post::whereBetween('created_at', [today()->startOfDay(), today()->endOfDay()])->get(). It produces a plain BETWEEN clause that the optimizer can serve from an index.
Carbon::today() use? Carbon uses PHP’s default timezone, which Laravel sets from config/app.php‘s timezone key. If that’s 'UTC' but your created_at values are stored in local time (or vice versa), you’ll see rows appear to slip across the day boundary. Either keep both sides UTC or pass a zone-aware constructor: Carbon::today('Asia/Dhaka').
Related guides
- How to Install Laravel on Ubuntu — bootstrap the Laravel 11 environment.
- How to Get Current Month Records in Laravel Eloquent — the month-scope counterpart.
- How to Count Rows in Laravel Eloquent — combine today’s filter with a count.
- How to Check if a Record Exists in Laravel — the lightweight existence check.
References
Official Laravel query builder docs (whereDate, whereBetween): laravel.com/docs/queries.