spatie/laravel-data
Create rich, typed data objects for Laravel that replace form requests and API transformers. Automatically map from requests, validate with inferred rules, transform to resources (with lazy/partial fields), and generate TypeScript definitions from the same source.
Installation:
composer require spatie/laravel-data
Ensure you have PHP 8.2+ and Laravel 10+ (or newer, as per latest compatibility).
Define a Data Class:
Create a class extending Spatie\LaravelData\Data with typed properties:
use Spatie\LaravelData\Data;
class UserData extends Data
{
public function __construct(
public string $name,
public int $age,
) {}
}
First Use Case: Instantiate directly or from request data:
// Direct instantiation
$user = new UserData(name: 'John', age: 30);
// From request (auto-validation)
$user = UserData::fromRequest(request());
#[Max(100)] for property-level validation.php artisan data:typescript to generate frontend types.Request Handling: Replace FormRequests with Data classes for validation and type safety:
class StoreUserRequest extends FormRequest {
public function rules(): array {
return UserData::rules(); // Auto-generates rules from Data class
}
}
API Responses: Use Data classes as API resources:
class UserResource extends JsonResource {
public function toArray($request): array {
return $this->resource->toArray(); // Converts Data to array
}
}
Eloquent Integration: Cast model attributes as Data:
use Spatie\LaravelData\Casts\Data;
class User extends Model {
protected $casts = [
'metadata' => Data::class,
];
}
Lazy Properties: Defer computation until accessed:
class UserData extends Data {
public function __construct(public string $name) {}
public function fullName(): string {
return "User: {$this->name}";
}
}
$data = UserData::from($request->all());
$data->validate(); // Throws ValidationException on failure
php artisan data:typescript
DataCollection for arrays of Data:
$users = DataCollection::from(UserData::class, $rawUsers);
Validation Rules Overrides:
rules() method always run, even if properties have defaults (fixed in v4.23.0).class UserData extends Data {
public function __construct(
public string $name,
public ?string $email = null,
) {}
public static function rules(): array {
return [
'email' => ['required_if:name,John'], // Now works!
];
}
}
PHP 8.4+ Dependencies:
phpdocumentor/reflection-docblock is compatible.Lazy Properties in Casts:
toArray() by default. Use #[Lazy] attribute or override toArray().TypeScript Generation:
cursor) may need manual fixes (see #1098).->validate() to catch issues early:
try {
$data->validate();
} catch (ValidationException $e) {
dd($e->errors());
}
php artisan view:clear) if Data classes break after updates.Data casts are registered in $casts with the full namespace.Custom Validation Attributes:
Extend Spatie\LaravelData\Attributes\ValidationAttribute for reusable rules:
#[Attribute]
class CustomRule extends ValidationAttribute {
protected string $rule = 'custom_rule';
}
Data Transformers:
Override toArray() or use #[MapTo] to customize output:
class UserData extends Data {
#[MapTo('user_name')]
public string $name;
}
TypeScript Templates:
Customize generated TS types via config/data.php:
'typescript' => [
'template' => resource_path('templates/data.ts.hbs'),
],
Database Constraints:
Use #[DatabaseConstraint] to enforce DB-level rules (v4.22.0+):
#[DatabaseConstraint('unique', 'users', 'email')]
public string $email;
How can I help you explore Laravel packages today?