What Is a Laravel Model and How It Interacts With the Database: A Complete Guide

A Laravel model is a PHP class that extends Illuminate\Database\Eloquent\Model to represent a database table, providing an object-oriented interface for CRUD operations, relationships, and query scopes through the Eloquent ORM layer.

In the laravel/framework repository, the model layer serves as the primary abstraction for database interaction. Rather than writing raw SQL, developers extend the base Model class to define table mappings, attribute casting, and business logic. This approach centralizes data access patterns within expressive PHP classes that handle everything from simple lookups to complex relational queries.

Core Architecture and Table Mapping

At the foundation of every Laravel model lies the Illuminate\Database\Eloquent\Model class, located in src/Illuminate/Database/Eloquent/Model.php. When you create a new model, you extend this base class to inherit its database interaction capabilities.

By default, Laravel infers the associated table name by taking the class name, converting it to snake_case, and pluralizing it. For example, a User model automatically maps to the users table. You can override this convention by explicitly setting the $table property:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $table = 'blog_posts';
    
    protected $fillable = ['title', 'body', 'user_id'];
    
    public function author()
    {
        return $this->belongsTo(User::class);
    }
}

The $fillable and $guarded properties play a critical role in mass assignment security. The $fillable array explicitly lists which columns can be bulk-assigned via Model::create() or update(), while $guarded specifies columns that should never be mass-assigned.

The Query Pipeline: From Model to SQL

Behind every model query, the Eloquent architecture delegates to two specialized builder classes. When you invoke methods like where() or find() on a model, you are actually interacting with Illuminate\Database\Eloquent\Builder, found in src/Illuminate/Database/Eloquent/Builder.php.

This Eloquent-specific builder constructs fluent query objects that ultimately rely on the lower-level Illuminate\Database\Query\Builder (src/Illuminate/Database/Query/Builder.php) to generate and execute raw SQL statements. This separation allows Eloquent to handle model-specific concerns—such as eager loading and relationship resolution—while the Query Builder manages database-agnostic SQL generation.

Creating and Querying Records

Defining a minimal Laravel model requires only extending the base class and optionally specifying fillable attributes:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $fillable = ['name', 'price', 'stock'];
}

With the model defined, you can persist data using either mass assignment or manual property assignment:

// Mass assignment via create()
$product = Product::create([
    'name' => 'Laravel T-Shirt',
    'price' => 19.99,
    'stock' => 150,
]);

// Manual assignment and save()
$product = new Product;
$product->name = 'Laravel Mug';
$product->price = 9.99;
$product->save();

Retrieving records leverages the fluent interface provided by the Eloquent Builder:

// Retrieve all records
$allProducts = Product::all();

// Find by primary key
$product = Product::find(1);

// Complex constraints
$expensive = Product::where('price', '>', 50)
    ->orderBy('price', 'desc')
    ->take(10)
    ->get();

Defining Relationships and Eager Loading

Laravel models define relationships through methods that return relationship objects defined in src/Illuminate/Database/Eloquent/Relations/Relation.php. These methods—hasOne(), hasMany(), belongsTo(), and belongsToMany()—establish links between models without requiring manual join logic.

Consider an Order model that connects to multiple Product records via a many-to-many relationship:

class Order extends Model
{
    public function products()
    {
        return $this->belongsToMany(Product::class)
            ->withPivot('quantity');
    }
}

You can then attach records or eager-load them to avoid N+1 query issues:

// Attach with pivot data
$order->products()->attach($productId, ['quantity' => 2]);

// Eager load relationship data
$orders = Order::with('products')->get();

Query Scopes, Accessors, and Mutators

Models encapsulate reusable query logic through scopes. Local scopes use the scope prefix and can be chained fluently, while global scopes apply automatically to all queries on the model via the booted() method.

class User extends Model
{
    // Global scope applied automatically
    protected static function booted()
    {
        static::addGlobalScope('active', function ($builder) {
            $builder->where('active', true);
        });
    }
    
    // Local scope for chaining
    public function scopeAdmins($query)
    {
        return $query->where('role', 'admin');
    }
    
    // Mutator for password hashing
    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = bcrypt($value);
    }
}

// Usage
$admins = User::admins()->get();

Accessors transform attribute data on retrieval. Define an accessor by creating a method with the get prefix and Attribute suffix:

public function getFullNameAttribute()
{
    return "{$this->first_name} {$this->last_name}";
}

Access this computed property as if it were a database column: $user->full_name.

Extending Models with Traits

The Laravel framework distributes additional functionality through traits that developers include in their models. The HasFactory trait (src/Illuminate/Database/Eloquent/Concerns/HasFactory.php) enables model factories for testing and database seeding, while the SoftDeletes trait (src/Illuminate/Database/Eloquent/SoftDeletes.php) adds soft-delete functionality by maintaining a deleted_at timestamp instead of permanently removing records.

Summary

  • Laravel models are PHP classes extending Illuminate\Database\Eloquent\Model that map to database tables and encapsulate data logic.
  • Table mapping follows naming conventions but can be customized via the $table property, while $fillable and $guarded protect against mass-assignment vulnerabilities.
  • Query execution flows through the Eloquent Builder (src/Illuminate/Database/Eloquent/Builder.php) to the underlying Query Builder (src/Illuminate/Database/Query/Builder.php).
  • Relationships are defined via methods returning relation objects, enabling clean traversal of linked records without manual SQL joins.
  • Scopes and accessors allow you to encapsulate reusable query constraints and attribute transformations directly within the model class.

Frequently Asked Questions

What is the default table naming convention for a Laravel model?

By default, Laravel converts the model class name to snake_case and pluralizes it to determine the table name. For example, a User model expects a table named users, while BlogPost expects blog_posts. Override this by setting the protected $table property in your model class.

How does mass assignment protection work in Laravel models?

Mass assignment protection prevents users from modifying unexpected fields during bulk updates. The $fillable array explicitly whitelists allowed fields, while the $guarded array blacklists protected fields. Only one of these properties should be used per model. When calling Model::create() or update(), Laravel checks these arrays before applying input data.

What is the difference between the Eloquent Builder and the Query Builder?

The Eloquent Builder (src/Illuminate/Database/Eloquent/Builder.php) is model-aware and handles relationship eager loading, model hydration, and Eloquent-specific methods like find(). The Query Builder (src/Illuminate/Database/Query/Builder.php) is a lower-level, database-agnostic SQL generator that constructs the actual queries. Eloquent Builder delegates SQL generation to the Query Builder while adding ORM functionality on top.

How do I define a custom relationship between two Laravel models?

Define a relationship method in your model that returns one of the relationship types: hasOne(), hasMany(), belongsTo(), or belongsToMany(). These methods are defined in the base Relation class (src/Illuminate/Database/Eloquent/Relations/Relation.php). For example, return $this->belongsTo(User::class) establishes a foreign key relationship, allowing you to access related data via $model->user or query it via $model->user()->where('active', true)->first().

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →