Skip to content

Field Types & Primary Keys

Fields are declared as name:type pairs, comma-separated:

bash
php artisan make:fullapi Product --fields="name:string,price:decimal,stock:integer,meta:json"

Supported types

TypeDatabase columnPHP typeValidation rule
stringVARCHAR(255)stringstring|max:255
textTEXTstringstring
integer / intINTEGERintinteger
bigintBIGINTEGERintinteger
boolean / boolBOOLEANboolboolean
float / decimalDECIMAL(8,2)floatnumeric
jsonJSONarrayjson
date / datetime / timestampTIMESTAMPDateTimeInterfacedate
uuidUUIDstringuuid
enum(a,b,...)ENUM('a','b')backed enum + castRule::enum()

Every type flows through the whole stack: migration column, validation rules, model cast, factory value, DTO property type and PHPDoc @property.

Native enum fields

bash
php artisan make:fullapi Article --fields="title:string,status:enum(draft,published,archived)"

One field definition produces the entire chain:

One enum field expands into five coherent files

  • app/Enums/Status.php: a backed enum Status: string with a case per value
  • Model: 'status' => \App\Enums\Status::class in $casts and @property \App\Enums\Status $status in the PHPDoc
  • Request: Rule::enum(Status::class) validation
  • Factory: fake()->randomElement(Status::cases())
  • Migration: $table->enum('status', ['draft', 'published', 'archived'])

In a schema file:

yaml
status: enum(draft,published) default=draft

Custom primary keys

Append :primary (CLI) or the primary modifier (schema file) to make a field the primary key instead of the default auto-increment id:

bash
php artisan make:fullapi Country --fields="code:string:primary,name:string"

The whole stack follows automatically:

  • Migration: $table->string('code')->primary(), no $table->id()
  • Model: $primaryKey, $incrementing = false, $keyType declared
  • Incoming relations: the FK is named country_code, typed like the key, with ->references('code') in the migration and exists:countries,code in validation
  • Generated tests use getKey() so they pass with either key style

Nullable, unique and defaults

The --fields string syntax keeps to name:type. For per-field constraints, use either the interactive wizard or a schema file, which accepts a shorthand or a mapping:

yaml
fields:
  title: string
  slug: string unique
  content: text nullable
  views: { type: integer, default: 0 }