FleetbaseFleetbase

Migrations

Define database migrations for your extension. They live under server/migrations/, follow Fleetbase's UUID + public_id conventions, and load automatically via the service provider.

Migrations

Migrations define the schema your extension owns. Fleetbase auto-loads them via your service provider ($this->loadMigrationsFrom(__DIR__ . '/../../migrations')), so they run alongside core migrations whenever someone runs php artisan migrate.

Where Migrations Live

server/
└── migrations/
    └── 2026_01_15_000000_create_widgets_table.php

Note: it's a flat migrations/ directory at server/migrations/, not server/database/migrations/. The path matches the standard Laravel package convention used across core-api and every shipped extension.

Naming Convention

Standard Laravel migration filenames: YYYY_MM_DD_HHMMSS_<verb>_<table_name>_table.php. Examples:

  • 2026_01_15_103000_create_widgets_table.php
  • 2026_01_18_142000_add_status_to_widgets_table.php
  • 2026_01_22_080000_add_foreign_keys_to_widgets_table.php

Foreign keys go in a separate later migration so the parent tables already exist when the constraint is added — see how pallet/server/migrations/ and storefront/server/migrations/ split creation and FK migrations into pairs.

Table-name Convention

Prefix your tables with your extension's namespace to avoid collisions:

Schema::create('my_extension_widgets', function (Blueprint $table) { ... });

Don't reuse a name that core uses (users, companies, orders, transactions, etc.). When in doubt, scope it.

Standard Column Pattern

Fleetbase models follow a consistent shape — copy this skeleton for any organization-scoped resource:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::create('my_extension_widgets', function (Blueprint $table) {
            $table->increments('id');
            $table->char('uuid', 36)->nullable()->unique();          // primary identifier
            $table->string('public_id')->nullable()->unique();       // user-visible ID (e.g. "widget_a1b2c3d4")
            $table->char('company_uuid', 36)->nullable()->index();   // org scoping — required for shared infra
            $table->char('created_by_uuid', 36)->nullable()->index();
            $table->string('name');
            $table->text('description')->nullable();
            $table->json('meta')->nullable();
            $table->string('status')->default('active');
            $table->softDeletes();                                   // adds deleted_at
            $table->timestamps();                                    // adds created_at, updated_at
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('my_extension_widgets');
    }
};
ColumnWhy
uuid (char(36))Internal stable identifier — referenced by other tables via *_uuid foreign keys
public_idHuman-friendly ID surfaced via the API. Generated by HasPublicId trait on the model
company_uuidMulti-tenant scope. Every per-org table needs this, indexed
created_by_uuidAudit trail back to the users table
meta (json)Catch-all for extension-specific fields you don't want columns for
softDeletes()Standard across Fleetbase models — mirrors trash/restore
timestamps()Always

Foreign Keys

Add foreign keys in a separate migration that runs after the create migration:

return new class extends Migration {
    public function up(): void
    {
        Schema::table('my_extension_widgets', function (Blueprint $table) {
            $table->foreign('company_uuid')
                  ->references('uuid')->on('companies')
                  ->cascadeOnDelete();
            $table->foreign('created_by_uuid')
                  ->references('uuid')->on('users')
                  ->nullOnDelete();
        });
    }

    public function down(): void
    {
        Schema::table('my_extension_widgets', function (Blueprint $table) {
            $table->dropForeign(['company_uuid']);
            $table->dropForeign(['created_by_uuid']);
        });
    }
};

Reference uuid (the FB convention), not the integer id.

Running Migrations

In a development extension you'll typically run:

docker compose exec application php artisan migrate

If you've made schema changes during local iteration:

docker compose exec application php artisan migrate:fresh --seed

The console exposes a re-runnable scaffold via the flb CLIflb scaffold generates a starter migration when you create a new model.

Models

Models live under server/src/Models/. Extend Fleetbase\Models\Model (not Laravel's base Model) — the base wires in UUID generation, public-id generation, soft-deletes, JSON-cast helpers, and the activity log.

namespace MyOrg\MyExtension\Models;

use Fleetbase\Models\Model;
use Fleetbase\Traits\HasPublicId;
use Fleetbase\Traits\HasUuid;
use Fleetbase\Traits\TracksApiCredential;

class Widget extends Model
{
    use HasUuid;
    use HasPublicId;
    use TracksApiCredential;

    protected $table = 'my_extension_widgets';
    protected $publicIdType = 'widget';

    protected $fillable = ['name', 'description', 'meta', 'status', 'company_uuid', 'created_by_uuid'];

    protected $casts = [
        'meta' => 'array',
    ];
}

$publicIdType is the prefix of the generated public_id (e.g. widget_a1b2c3d4). Browse traits at packages/core-api/src/Traits.

Sandbox & Multi-tenant Considerations

Every Fleetbase install runs two databases — production and sandbox — with the same schema. The MigrateSandbox console command handles syncing migrations across both. By default your migrations run against both; if you have a migration that should only run in production, set the extension flag in composer.json:

"extra": {
    "fleetbase": {
        "sandbox-migrations": false
    }
}

Most extensions don't need this flag — by default migrations run against both production and sandbox, which is what you want for multi-tenant data.

Source

FileDescription
core-api/migrations/Core schema migrations — reference shapes
pallet/server/migrations/Reference extension migrations
storefront/server/migrations/Reference extension migrations
src/Console/Commands/MigrateSandbox.phpSandbox-aware migration runner
src/Traits/HasUuid.phpUUID auto-generation trait
src/Traits/HasPublicId.phppublic_id generation trait
Migrations | Fleetbase