zedisdog/laravel-schema-extend
Extend Laravel's schema builder with extra column types and helpers, making it easy to define database structures the framework doesn't support out of the box. Add custom columns to migrations and keep your schema expressive.
Install via Composer:
composer require zedisdog/laravel-schema-extend --dev
The package is a set of Blueprint macros that are registered through its service provider. On Laravel 5.5+ the provider is auto-discovered; on older versions add Zedisdog\LaravelSchemaExtend\LaravelSchemaExtendServiceProvider::class to config/app.php. Confirm it is registered before running migrations — the macros are only available to Schema::create/Schema::table closures once the provider has booted.
Where to look first:
src/ directory for the Blueprint::macro(...) calls — these tell you the exact method name, default column name, and whether a foreign key/index is attached by default.vendor/zedisdog/laravel-schema-extend/README.md for the canonical method list.Illuminate\Database\Schema\Blueprint to see what the package is wrapping (usually unsignedBigInteger + foreign).First use case — collapse the common "foreign key to users" boilerplate:
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->user(); // user_id + FK to users.id
$table->string('title');
$table->timestamps();
});
instead of:
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
That is the day-to-day value: shorter migrations for convention-driven foreign keys.
Convention-based foreign keys. Use the package's shorthand for columns that always follow the same shape (owner, author, post, category). Reserve native foreignId()->constrained() for anything that needs custom table/column names or onDelete behavior — mixing both is fine as long as your team knows the rule.
Audit/timestamp helpers. If the package exposes timestampsTz-style helpers or soft-delete variants, standardize on them in a shared base migration or a trait so timezone columns are consistent across tables. This is where the package saves the most repeated code.
Nullable/soft relationships. For optional ownership, combine with nullable() (if the macro returns the column definition) or chain the package's nullable variant. Test the down() path — a nullable FK is dropped cleanly with the column on most drivers, but explicit dropForeign is safer cross-database.
Team consistency over cleverness. The package is most useful when it encodes house conventions: e.g., "every *_id FK to a standard table uses the shorthand." Write that into your migration style guide, otherwise developers will mix macro and native syntax and reviewers will not know which is authoritative.
Integration with models/factories. Nothing changes at the Eloquent layer — these are still normal integer columns. Keep belongsTo definitions and factory references aligned with whatever column name the macro produces (usually <singular>_id), because the package will silently use its own default if you omit the argument.
Rollback ordering. When a migration creates several shorthand FKs, dropping the table is usually enough, but if you split tables across migrations, drop child FKs (or the child table) before the parent table. php artisan migrate:rollback --step=1 per batch makes this predictable.
Extending the pattern. If your schema has a recurring shape the package does not cover, define your own macro in a service provider:
Blueprint::macro('tenant', function () {
return $this->unsignedBigInteger('tenant_id')->index();
});
This is the intended extension point — keep custom macros in one provider so they load for every migration.
composer.json and review it before upgrading Laravel. On modern Laravel (8+), foreignId('user_id')->constrained() covers most of what this package does, so consider it a stopgap rather than a long-term dependency.Blueprint; it does not change the query builder, model casts, or anything at runtime. Do not expect $table->user() to be understood by other tooling (IDE stubs, schema dumpers) without the provider loaded.RefreshDatabase, the provider must be registered in the test environment too. If migrations fail with "method does not exist," the provider is not booted — check php artisan about / config/app.php before debugging the migration itself.user_id). If you pass a custom name, verify the generated foreign key and index names do not exceed your database's identifier limit (MySQL: 64 chars). Long table names plus default FK naming is a common cause of "identifier name too long" errors.->index() on the column and the macro adds its own index, you can hit duplicate index errors. Read the macro source for exactly which index/constraint it adds.php artisan migrate --pretend to see the SQL the macros generate, and Schema::getColumnListing('posts') in tinker to confirm columns and naming. DB::getQueryLog() around the migration will not show schema DDL reliably on all drivers.$table->dropForeign(['user_id']) explicitly in down() when in doubt.DB::statement or native blueprint methods instead.How can I help you explore Laravel packages today?