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
jsonJSONarrayarray
dateDATEDateTimeInterfacedate
timeTIMEstringdate_format:H:i,H:i:s
datetimeDATETIMEDateTimeInterfacedate
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. Here is the code the command above writes, trimmed to the lines the enum touches:

php
namespace App\Enums;

enum ArticleStatus: string
{
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
}
php
/**
 * @property int $id
 * @property string $title
 * @property ArticleStatus $status
 * @property Carbon|null $created_at
 * @property Carbon|null $updated_at
 */
class Article extends Model
{
    use HasFactory;

    protected $fillable = ['title', 'status'];

    protected function casts(): array
    {
        return [
            'status' => ArticleStatus::class,
        ];
    }
}
php
public function rules(): array
{
    return [
        'title' => 'required|string|max:255',
        'status' => ['required', Rule::enum(ArticleStatus::class)],
    ];
}
php
public function definition(): array
{
    return [
        'title' => fake()->word(),
        'status' => fake()->randomElement(ArticleStatus::cases()),
    ];
}
php
Schema::create('articles', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->enum('status', ['draft', 'published', 'archived']);
    $table->timestamps();
});

The enum is named after the entity and the field, ArticleStatus here, so two entities can each have their own status.

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 }