# Laravel Casts: Best Practices for Eloquent Model Attributes

> Master Laravel casts for Eloquent models. Learn best practices for casting dates booleans and sensitive data using primitive types and custom classes for complex objects.

- Repository: [Laravel/framework](https://github.com/laravel/framework)
- Tags: best-practices
- Published: 2026-02-16

---

**Prioritize casting date fields, boolean flags, and sensitive data using primitive types, while reserving custom class casts for complex domain objects like money or coordinates.**

Laravel casts provide automatic type conversion between your database and Eloquent models, ensuring data integrity and reducing boilerplate. When working with the `laravel/framework` repository, understanding the internal casting mechanism in the `HasAttributes` trait helps you implement efficient, secure attribute handling. This guide covers which attribute types to prioritize and how to leverage primitive, enum, and custom casts effectively.

## How Laravel Casts Work Internally

The casting system resides in `Illuminate\Database\Eloquent\Concerns\HasAttributes`. During model initialization, the `initializeHasAttributes` method merges casts from the `$casts` property and any `casts()` method return value (lines 84‑87). All cast definitions are normalized to strings via `ensureCastsAreStringValues`.

When retrieving attributes, `castAttribute()` (lines 332‑390) checks against the `$primitiveCastTypes` array (lines 105‑133) to determine whether to apply built-in conversion logic or delegate to custom cast classes.

### Primitive vs. Custom Cast Types

Laravel distinguishes between lightweight primitive casts and heavyweight custom implementations:

| Type | Example | Use Case |
|------|---------|----------|
| **Primitive** | `'is_active' => 'boolean'` | Built-in types (bool, int, float, decimal, string, date, datetime, timestamp, array, json, collection, encrypted, hashed, immutable variants). No class loading overhead. |
| **Enum** | `'status' => OrderStatus::class` | PHP 8.1+ BackedEnum for type-safe domain values. |
| **Custom Class** | `'total' => Money::class` | Complex objects requiring transformation logic; must implement `CastsAttributes`. |
| **Attribute Object** | `price(): Attribute` | Modern syntax combining get/set with caching support. |

## Prioritizing Attribute Types for Laravel Casts

Based on the internal implementation and performance characteristics of `HasAttributes`, prioritize casting in this order:

### 1. Date and DateTime Fields

Always cast temporal columns. The `isDateCastable` method (lines 1715‑1717) identifies these fields for automatic Carbon conversion.

```php
protected $casts = [
    'published_at' => 'datetime',
    'archived_at' => 'immutable_datetime',
    'birth_date' => 'date:Y-m-d',
];

```

### 2. Boolean Flags

Prevent "truthy" string bugs by casting tinyint/boolean columns:

```php
protected $casts = [
    'is_active' => 'boolean',
    'is_admin' => 'bool',
];

```

### 3. Numeric Types

Use specific numeric casts for mathematical integrity:

```php
protected $casts = [
    'login_count' => 'integer',
    'rating' => 'float',
    'price' => 'decimal:2',
];

```

### 4. JSON and Array Structures

For columns storing structured data, use `array`, `json`, or `collection`. The `castAttributeAsJson` method (lines 616‑631) handles encoding:

```php
protected $casts = [
    'preferences' => 'array',
    'metadata' => 'json',
    'tags' => 'collection',
];

```

### 5. Encrypted and Hashed Values

Secure sensitive data automatically via `castAttributeAsEncryptedString` (lines 384‑390):

```php
protected $casts = [
    'api_key' => 'encrypted',
    'secrets' => 'encrypted:array',
    'password' => 'hashed',
];

```

### 6. PHP Enums

Type-safe domain constraints via `getEnumCastableAttributeValue` (lines 636‑642):

```php
use App\Enums\OrderStatus;

protected $casts = [
    'status' => OrderStatus::class,
];

```

### 7. Custom Value Objects

For complex domain logic, implement `CastsAttributes` and reference the class:

```php
use App\Casts\Money;

protected $casts = [
    'total' => Money::class,
];

```

The `getClassCastableAttributeValue` (lines 904‑926) and `setClassCastableAttribute` (lines 1249‑1269) methods invoke your custom logic.

## Modern Attribute Syntax

Laravel also provides the `Attribute` class for inline get/set definitions with caching support (stored in `$attributeCastCache`, lines 88‑92):

```php
use Illuminate\Database\Eloquent\Casts\Attribute;

protected function price(): Attribute
{
    return Attribute::make(
        get: fn ($value) => new Money($value / 100, 'USD'),
        set: fn (Money $money) => $money->getAmount() * 100,
    );
}

```

## Performance and Security Considerations

| Consideration | Implementation Detail |
|---------------|---------------------|
| **Avoid over-casting large JSON** | Casting forces full decode via `fromJson` on every model load. Use `json` only when necessary. |
| **Prefer primitives** | Primitive casts in `castAttribute` (lines 332‑390) avoid class instantiation overhead. |
| **Use immutable dates** | `immutable_datetime` returns `CarbonImmutable`, preventing accidental mutation. |
| **Validate cast strings** | `ensureCastsAreStringValues` normalizes definitions; always use strings or class names. |
| **Custom encryption** | Override `Json::encodeUsing`/`decodeUsing` or implement `CastsAttributes` for custom algorithms. |

## Summary

- **Start with primitive casts** for dates, booleans, integers, and JSON to leverage lightweight conversion in `HasAttributes::castAttribute`.
- **Secure sensitive data** using `encrypted` and `hashed` casts, which automatically invoke encryption logic before persistence.
- **Enforce domain constraints** with PHP 8.1+ BackedEnum casts via `getEnumCastableAttributeValue`.
- **Reserve custom class casts** for complex value objects requiring transformation logic, utilizing `CastsAttributes` implementations.
- **Consider Attribute objects** when you need combined get/set logic with built-in caching support.

## Frequently Asked Questions

### What is the difference between array and json casts in Laravel?

Both casts store data as JSON in the database, but `array` automatically decodes to a PHP array on retrieval, while `json` can return a stdClass object depending on the JSON decoder settings. Use `array` when you need associative array access and `json` when working with objects or raw JSON strings.

### How do I cast encrypted attributes in Laravel?

Use the `encrypted` or `encrypted:array` cast types in your `$casts` property. Laravel automatically encrypts values before saving and decrypts them when retrieving via the `castAttributeAsEncryptedString` method in `HasAttributes`. Ensure your application has a properly configured encryption key in the environment.

### Should I use custom cast classes or Attribute objects?

Use **Attribute objects** (introduced in Laravel 9) for simple get/set transformations that benefit from caching, as they store values in `$attributeCastCache`. Use **custom cast classes** implementing `CastsAttributes` when you need reusable transformation logic across multiple models or when handling complex value objects like Money or coordinates that require specific serialization formats.

### What are immutable date casts and when should I use them?

`immutable_date` and `immutable_datetime` casts return `CarbonImmutable` instances instead of mutable `Carbon` objects. Use these when you want to prevent accidental modification of date values after retrieval, ensuring that any changes to the date object don't affect other parts of your application holding references to the same model instance.