Pass an Expression instance to Laravel's migration default() method to define raw SQL functions, dynamic timestamps, and calculated defaults directly in your database schema.
In Laravel migrations, passing a scalar string to default() treats the value as a literal string in the generated SQL clause (DEFAULT 'CURRENT_TIMESTAMP'), causing syntax errors when attempting to call SQL functions.
To instruct the database engine to evaluate an SQL function upon insertion, wrap the value in an Illuminate\Database\Query\Expression.
Literal vs Expression
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Query\Expression;
use Illuminate\Support\Facades\Schema;
Schema::create('orders', function (Blueprint $table) {
$table->id();
// Static literal (escaped as a string)
$table->string('status')->default('pending');
// ❌ Quotes literal string: DEFAULT 'CURRENT_TIMESTAMP'
// $table->timestamp('placed_at')->default('CURRENT_TIMESTAMP');
// ✅ Unquoted SQL expression: DEFAULT CURRENT_TIMESTAMP
$table->timestamp('placed_at')->default(new Expression('CURRENT_TIMESTAMP'));
// MySQL 8.0+ expressions require enclosing parentheses
$table->uuid('uuid')->default(new Expression('(UUID())'));
$table->json('settings')->default(new Expression('(JSON_OBJECT())'));
// PostgreSQL expressions
// $table->uuid('id')->primary()->default(new Expression('gen_random_uuid()'));
// $table->jsonb('preferences')->default(new Expression("'{}'::jsonb"));
});
Key Considerations
- Engine Evaluation: Defaults set via
Expressionare evaluated directly by the database engine, ensuring valid fallback values even during raw SQL queries, external ETL scripts, or bulk inserts outside Eloquent. - MySQL 8.0+ Syntax: Functional default expressions in MySQL must be enclosed in parentheses (e.g.
(UUID())or(JSON_ARRAY())). - Portability: Normal static values (
'pending',0,true) should use standarddefault('pending')to maintain database-agnostic portability.
Tags:
Laravel Migrations Database Eloquent SQL