Eloquent ORM Basics

Eloquent is Laravel's built-in ORM (Object-Relational Mapper), and it's the tool you'll use for the overwhelming majority of database work in a Laravel application. It follows the ActiveRecord pattern: every database table gets a corresponding PHP class (a "model"), and every row in that table is represented, at runtime, as an instance of that model class. Instead of writing raw SQL strings, you work with objects and method calls, and Eloquent translates that into SQL behind the scenes.

Generating a Model

Like most things in Laravel, models are scaffolded with Artisan rather than created by hand:

# From your project's terminal
php artisan make:model Article

This creates app/Models/Article.php, an empty class extending Eloquent's base Model class. A commonly used shortcut adds the -m flag, which generates a matching database migration file at the same time — migrations are covered fully in the next lesson, Migrations & Seeders, but it's worth knowing this shortcut exists since you'll use it constantly:

# Generates both the model AND a migration for the "articles" table
php artisan make:model Article -m

Eloquent's Naming Conventions

Eloquent leans heavily on convention over configuration — as long as you follow its naming rules, you never have to manually tell a model which table it maps to.

ConventionExample
Table nameA model named Article (singular, StudlyCase) automatically maps to a table named articles (plural, snake_case). A model named OrderItem maps to order_items.
Primary keyAssumed to be a column named id, auto-incrementing, unless you override it.
Timestampscreated_at and updated_at columns are set and updated automatically by Eloquent whenever a row is created or saved — you never set these yourself unless you explicitly disable this behavior with public $timestamps = false; on the model.
Note: All of these conventions can be overridden — a protected $table = 'blog_posts'; property, for instance, points a model at a differently-named table — but sticking with the defaults keeps your codebase predictable and is strongly recommended unless you have a real reason not to.

Basic CRUD with Eloquent

Reading and writing rows through a model reads almost like plain English:

<?php
// Read all rows from the "articles" table
$articles = Article::all();

// Find one row by its primary key (returns null if not found)
$article = Article::find(1);

// Create a new row in one call
$article = Article::create([
    'title' => 'Getting Started With Eloquent',
    'body' => 'Eloquent makes database work feel natural...',
]);

Mass Assignment and $fillable

That Article::create([...]) call is called mass assignment — passing an entire array of column values at once, instead of setting each property individually. Eloquent requires you to explicitly opt in to which fields are allowed to be mass-assigned, via a $fillable property on the model:

<?php
// app/Models/Article.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $fillable = ['title', 'body'];
}
Why this protection exists: without $fillable, a form that blindly passes $request->all() into create() would let an attacker submit any field name they like in their form data — including something like is_admin or role — and have it silently written straight to the database, even though your actual form never intended to expose that field. Listing only the genuinely safe, user-editable columns in $fillable closes that door: anything not listed is simply ignored during mass assignment.

Saving via an Instance

Mass assignment isn't the only way to create a row — you can also build up a new model instance property by property and call save() when it's ready:

<?php
$article = new Article();
$article->title = 'Getting Started With Eloquent';
$article->body = 'Eloquent makes database work feel natural...';
$article->save();

This form doesn't need $fillable at all — mass assignment protection only applies when you're passing an array into methods like create() or fill(), not when setting individual properties directly.

Updating and Deleting

<?php
// Update an existing row
$article = Article::find(1);
$article->update([
    'title' => 'An Updated Title',
]);

// Delete a row
$article->delete();

Like create(), the array passed to update() is also mass assignment, so it's governed by the same $fillable rules on the model.

A Full Worked Example: A Controller Action

Putting several of these together, a typical controller method that stores a new article looks like this:

<?php
// app/Http/Controllers/ArticleController.php
public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|max:255',
        'body' => 'required',
    ]);

    $article = Article::create($validated);

    return redirect('/articles/' . $article->id);
}

Validation (from the previous lesson) protects against bad or missing data; $fillable on the Article model protects against unwanted fields sneaking into the mass-assigned array; and create() does the actual insert, timestamps included automatically, returning the freshly created model — complete with its new id — ready to use immediately, as shown in the redirect above.

Next up: Real applications rarely have just one isolated model — articles have authors, authors have profiles, and so on. Head to Eloquent Relationships to connect your models together.