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

> Learn what a Laravel model is and how it simplifies database interactions. Discover its role in CRUD operations, relationships, and query scopes with Eloquent ORM.

- Repository: [Laravel/framework](https://github.com/laravel/framework)
- Tags: tutorial
- Published: 2026-02-19

---

**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`](https://github.com/laravel/framework/blob/main/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:

```php
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`](https://github.com/laravel/framework/blob/main/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`](https://github.com/laravel/framework/blob/main/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:

```php
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:

```php
// 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:

```php
// 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`](https://github.com/laravel/framework/blob/main/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:

```php
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:

```php
// 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.

```php
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:

```php
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`](https://github.com/laravel/framework/blob/main/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`](https://github.com/laravel/framework/blob/main/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`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Eloquent/Builder.php)) to the underlying Query Builder ([`src/Illuminate/Database/Query/Builder.php`](https://github.com/laravel/framework/blob/main/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`](https://github.com/laravel/framework/blob/main/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`](https://github.com/laravel/framework/blob/main/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`](https://github.com/laravel/framework/blob/main/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()`.