FormatterHQ

JSON to Laravel Model & Migration

Paste one JSON record and get an Eloquent model with $fillable, casts and belongsTo relations, plus a matching create-table migration.

Input JSON
Output PHP
Ready.

How to use the JSON to Laravel Model & Migration

  1. Paste a single JSON object, such as one record from an API response.
  2. Set the Model name (for example Post) and, if needed, a custom Table name.
  3. Click Generate to build the model and migration.
  4. Save the first part as app/Models/Post.php and the second as a new file in database/migrations, then run php artisan migrate.

JSON to Laravel model and migration

This JSON to Laravel model generator turns a sample record into two files at once: an Eloquent model and the migration that creates its table. It is handy when you are storing data from a third-party API, importing a JSON export into MySQL, or scaffolding a model from a front-end mockup. The column types, $fillable list, attribute casts and belongsTo relations are all inferred from the values in your JSON.

Example

From the sample blog post record (with user_id, price, is_published, published_at, a nested meta object and timestamps), the tool generates this model:

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'title',
        'slug',
        'body',
        'price',
        'is_published',
        'published_at',
        'meta',
    ];

    protected function casts(): array
    {
        return [
            'price' => 'decimal:2',
            'is_published' => 'boolean',
            'published_at' => 'datetime',
            'meta' => 'array',
        ];
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

and this migration body:

Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->string('title');
    $table->string('slug');
    $table->string('body');
    $table->decimal('price', 10, 2);
    $table->boolean('is_published')->default(false);
    $table->timestamp('published_at')->nullable();
    $table->json('meta')->nullable();
    $table->timestamps();
});

The output uses the conventions of current Laravel releases: an anonymous migration class and the casts() method introduced in Laravel 11. On Laravel 10 or earlier, move the array into a protected $casts property instead.

How columns are inferred

JSON valueMigrationCast
Integer ending in _idforeignId()->constrained()->cascadeOnDelete()plus a belongsTo method
Other integerinteger, or bigInteger above 2,147,483,647integer
Decimal numberdecimal(10, 2)decimal:2
true/falseboolean()->default(false)boolean
ISO date / date-timedate / timestamp, nullabledate / datetime
Object or arrayjson()->nullable()array
UUID stringuuidnone
String longer than 255 charstextnone
Other string / nullstring / string()->nullable()none

Special fields

  • id is skipped because the migration always starts with $table->id().
  • created_at and updated_at become $table->timestamps(). Without them, the model gets public $timestamps = false; so Eloquent does not try to write them.
  • deleted_at adds $table->softDeletes() and the SoftDeletes trait.
  • A field named exactly email, e_mail or email_address gets a unique() index (other names such as user_email do not); a password field gets the hashed cast and is added to $hidden.
  • camelCase keys such as publishedAt are converted to snake_case columns, which is the Laravel convention.

Options

Model name is converted to PascalCase and pluralized for the table name (Category becomes categories). If your table does not follow that rule, fill in Table; the model then gets a protected $table property.

Review before migrating

One record cannot reveal everything. Check the string lengths, decide which columns should be nullable, and confirm the foreign keys: author_id will be linked to an authors table, which may need to be constrained('users'). Indexes other than unique on email are not guessed, so add index() to columns you filter or sort by often, such as slug or published_at. If you paste an array, the keys of all records are merged: a column becomes nullable() when any record has null for it or lacks the key, which helps catch optional fields.

Privacy

Generation happens in your browser, so records with personal data stay on your computer. Already have the SQL? Use SQL to Laravel migration instead. You can also convert data with JSON to PHP array for seeders, or create plain classes with JSON to PHP.

Frequently asked questions

Which Laravel version does the generated code target?
Laravel 11 and later, which use the casts() method and anonymous migration classes. For Laravel 9 or 10, keep the migration as is and turn casts() into a protected $casts = [...] property.
Why did user_id become a foreignId with cascadeOnDelete?
Integer fields ending in _id are treated as foreign keys to the plural table, so user_id references users.id. Cascade delete is a common default; change it to nullOnDelete() or remove it if deleting the parent should not delete these rows.
Can I generate a model from a JSON array?
Yes. The objects in the array are merged, so a field that appears in any record is included. The column takes the widest type found across the records (an integer in one record and a decimal in another gives decimal), and it is marked nullable when any record has null for the field or lacks it.
Why is my text column a string instead of text?
Strings up to 255 characters become string (VARCHAR 255). If the sample value is short but real values can be long, such as an article body, change the column to text or longText.
Does it create a factory or seeder too?
No, only the model and migration. The model includes the HasFactory trait, so you can run php artisan make:factory PostFactory and fill it in.

Last updated October 3, 2026

Guides

Related tools