---
url: /laravel-api-generator/guide/field-types.md
---
# 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

| Type | Database column | PHP type | Validation rule |
|------|----------------|----------|-----------------|
| `string` | `VARCHAR(255)` | `string` | `string\|max:255` |
| `text` | `TEXT` | `string` | `string` |
| `integer` / `int` | `INTEGER` | `int` | `integer` |
| `bigint` | `BIGINTEGER` | `int` | `integer` |
| `boolean` / `bool` | `BOOLEAN` | `bool` | `boolean` |
| `float` / `decimal` | `DECIMAL(8,2)` | `float` | `numeric` |
| `json` | `JSON` | `array` | `array` |
| `date` | `DATE` | `DateTimeInterface` | `date` |
| `time` | `TIME` | `string` | `date_format:H:i,H:i:s` |
| `datetime` | `DATETIME` | `DateTimeInterface` | `date` |
| `timestamp` | `TIMESTAMP` | `DateTimeInterface` | `date` |
| `uuid` | `UUID` | `string` | `uuid` |
| `enum(a,b,...)` | `ENUM('a','b')` | backed enum + cast | `Rule::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:

::: code-group

```php [Enum]
namespace App\Enums;

enum ArticleStatus: string
{
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
}
```

```php [Model]
/**
 * @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 [Request]
public function rules(): array
{
    return [
        'title' => 'required|string|max:255',
        'status' => ['required', Rule::enum(ArticleStatus::class)],
    ];
}
```

```php [Factory]
public function definition(): array
{
    return [
        'title' => fake()->word(),
        'status' => fake()->randomElement(ArticleStatus::cases()),
    ];
}
```

```php [Migration]
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](/guide/generating#interactive-wizard) or a [schema file](/guide/schema-files), which accepts a shorthand or a mapping:

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