Schema Builder
Database-agnostic schema definitions with Blueprint.
The Schema Builder provides a fluent, database-agnostic way to define tables. It generates the appropriate SQL for SQLite, MySQL, and PostgreSQL automatically.
Creating Tables #
use VelvetCMS\Database\Schema\Schema;
use VelvetCMS\Database\Schema\Blueprint;
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug', 100);
$table->text('content');
$table->timestamps();
});
Dropping Tables #
Schema::drop('posts');
// Only if it exists
Schema::dropIfExists('posts');
Column Types #
Primary Keys #
$table->id(); // BIGINT auto-increment primary key named 'id'
$table->id('custom_id'); // Custom column name
Strings #
$table->string('name'); // VARCHAR(255)
$table->string('code', 50); // VARCHAR(50)
$table->text('description'); // TEXT
$table->longText('body'); // LONGTEXT (MySQL) / TEXT (PostgreSQL, SQLite)
Numbers #
$table->integer('count'); // INTEGER
$table->integer('count', true); // INTEGER AUTO_INCREMENT
$table->integer('count', false, true); // INTEGER UNSIGNED
$table->bigInteger('views'); // BIGINT
$table->bigInteger('id', true, true); // BIGINT UNSIGNED AUTO_INCREMENT
Booleans #
$table->boolean('active'); // BOOLEAN (or TINYINT(1) on MySQL)
JSON #
$table->json('metadata'); // JSON (MySQL) / JSONB (PostgreSQL) / TEXT (SQLite)
Timestamps #
$table->timestamp('published_at'); // TIMESTAMP
$table->timestamps(); // created_at and updated_at, both nullable
Column Modifiers #
Chain modifiers after the column definition:
$table->string('nickname')->nullable(); // Allow NULL
$table->string('status')->default('draft'); // Default value
$table->integer('views')->unsigned(); // Unsigned integer
$table->timestamp('created_at')->useCurrent(); // DEFAULT CURRENT_TIMESTAMP
$table->string('email')->nullable()->default(null);
Indexes #
Regular Index #
// On last defined column
$table->string('email')->index();
// On specific column(s)
$table->index('email');
$table->index(['first_name', 'last_name']);
// With custom name
$table->index('email', 'idx_users_email');
Unique Index #
$table->string('email')->unique();
$table->unique('slug');
$table->unique(['tenant_id', 'slug']); // Composite unique
Primary Key #
$table->primary('id');
$table->primary(['tenant_id', 'id']); // Composite primary key
Foreign Keys #
$table->bigInteger('user_id', false, true); // Unsigned bigint
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
Full foreign key example:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->bigInteger('author_id', false, true);
$table->string('title');
$table->text('content');
$table->timestamps();
$table->foreign('author_id')
->references('id')
->on('users')
->onDelete('cascade')
->onUpdate('cascade');
});
Complete Example #
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->bigInteger('post_id', false, true);
$table->bigInteger('user_id', false, true)->nullable();
$table->string('author_name')->nullable();
$table->string('author_email')->nullable();
$table->text('body');
$table->string('status', 20)->default('pending');
$table->timestamps();
$table->index('status');
$table->index(['post_id', 'status']);
$table->foreign('post_id')
->references('id')
->on('posts')
->onDelete('cascade');
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('set null');
});
Driver Differences #
The Schema Builder handles dialect differences automatically:
| Feature | SQLite | MySQL | PostgreSQL |
|---|---|---|---|
| Auto-increment | INTEGER PRIMARY KEY |
AUTO_INCREMENT |
SERIAL |
| Boolean | INTEGER |
TINYINT(1) |
BOOLEAN |
| Unsigned | Ignored | UNSIGNED |
Ignored |
| longText | TEXT |
LONGTEXT |
TEXT |
| JSON | TEXT |
JSON |
JSONB |
If you need truly driver-specific DDL, use raw SQL migrations instead.