On this page
Overview
Laravel Enumify turns the PHP enums in your Laravel app into TypeScript files, so the frontend and backend share one source of truth for statuses, roles and types. Each enum becomes a const object plus a matching type, with a Utils object holding its labels and custom methods.
Generation is one Artisan command, enumify:sync, and the companion Vite plugin Enumify runs it for you during dev and build. The package also ships enumify:refactor, which finds hardcoded enum values in your code and rewrites them to enum references. It is MIT licensed and maintained by the DevWizard core team.
Features
- One TypeScript file per enum, with a barrel
index.tsyou can switch off. - Cases exported as an
as constobject, plus a type with the same name. label()or a staticlabels()method becomes alabelhelper.- Public, non-static, zero-argument methods that return
string,int,float,boolor a nullable or union of those become helpers too. Boolean methods become predicates. - A generated
options()helper that lists every case. - File names in
kebab,camelorpascalcase. - Include and exclude filters that accept class names or glob patterns.
- Optional localization mode for React or Vue, generating a
use...Utilshook instead of a static object. - Manifest file with hashes so unchanged files are skipped, plus
--dry-run,--forceand JSON output. enumify:refactorfor replacing hardcoded values and normalizing case names to UPPERCASE.- A
HasLabelscontract and anEnumHelperstrait for the PHP side.
Requirements
- PHP 8.2 or newer.
- Laravel 10, 11, 12 or 13 (
illuminate/supportandilluminate/contracts). - For automatic syncing, the npm package Vite plugin Enumify, which supports Vite 4 to 8 and Node 18 or newer.
Installation
composer require devwizardhq/laravel-enumifyThen scaffold the output folder:
php artisan enumify:installThe installer creates the output directory and a .gitkeep file, prints the .gitignore lines to add, can append them, and offers to publish the config. It also offers to install the Vite plugin with the package manager it detects from your lock file. To do that step yourself:
pnpm add -D @devwizard/vite-plugin-enumifyConfiguration
Publish the config file:
php artisan vendor:publish --tag="enumify-config"The keys in config/enumify.php:
| Key | Default | Description |
|---|---|---|
paths.enums |
['app/Enums'] |
Directories scanned for enums |
paths.models |
['app/Models'] |
Directories scanned for enum casts by enumify:refactor |
paths.output |
'resources/js/enums' |
Where TypeScript files are written |
naming.file_case |
'kebab' |
File name case: kebab, camel or pascal |
features.generate_union_types |
true |
Export a type next to each const object |
features.generate_label_maps |
true |
Generate the label helper |
features.generate_method_maps |
true |
Generate helpers for custom methods |
features.generate_index_barrel |
true |
Write an index.ts barrel |
localization.mode |
'none' |
none, react or vue |
runtime.watch |
true |
Read by the Vite plugin to decide whether to watch |
filters.include |
[] |
Only these enums, by class name or glob; empty means all |
filters.exclude |
[] |
Skip these enums |
refactor.exclude |
vendor, node_modules, storage and similar | Paths enumify:refactor never scans |
Usage
Write a normal PHP enum:
namespace App\Enums;
enum OrderStatus: string
{
case PENDING = 'pending';
case SHIPPED = 'shipped';
public function label(): string
{
return match ($this) {
self::PENDING => 'Pending',
self::SHIPPED => 'Shipped',
};
}
public function color(): string
{
return match ($this) {
self::PENDING => 'yellow',
self::SHIPPED => 'green',
};
}
}Generate the TypeScript:
php artisan enumify:syncThe file resources/js/enums/order-status.ts exports OrderStatus (the const object and the type) and OrderStatusUtils with label, color and options helpers. Import it in the frontend:
import { OrderStatus, OrderStatusUtils } from '@/enums/order-status';
const status: OrderStatus = OrderStatus.PENDING;
OrderStatusUtils.label(status);
OrderStatusUtils.color(status);
OrderStatusUtils.options();With the Vite plugin in place, the sync runs on every build and again when files in your enum directories change, so you rarely run it by hand.
API Reference
Artisan commands
| Command | Purpose |
|---|---|
enumify:install |
Create the output folder, .gitkeep, gitignore lines and optional plugin install. Option --force |
enumify:sync |
Generate TypeScript files from the configured enums |
enumify:refactor |
Replace hardcoded enum values and normalize case names |
enumify:sync options:
| Option | Description |
|---|---|
--force |
Rewrite every file even if unchanged |
--dry-run |
Show what would be generated without writing |
--only= |
Generate a single enum by fully qualified class name |
--format= |
table (default) or json |
enumify:refactor options:
| Option | Short | Description |
|---|---|---|
--fix |
-f |
Apply the changes |
--dry-run |
-d |
Preview without changing files |
--enum= |
-e |
Target one enum by short name |
--path= |
-p |
Limit the scan to a directory |
--interactive |
-i |
Guided prompts |
--json |
-j |
JSON output |
--backup |
Back up files before changing them | |
--include= |
File patterns to include, repeatable | |
--exclude= |
Paths or patterns to skip, repeatable | |
--report= |
Write a report as json, csv or md |
|
--detailed |
Show code context | |
--normalize-keys |
Convert case names to UPPERCASE and update references |
The refactor command only touches columns that have an enum cast on a model found in paths.models.
PHP helpers
DevWizardHQ\Enumify\Contracts\HasLabels declares label(): string.
DevWizardHQ\Enumify\Concerns\EnumHelpers is a trait for backed enums with these static methods:
| Method | Returns |
|---|---|
options(string $label = 'label') |
Array of value to label pairs |
selectOptions(string $label = 'label') |
List of value and label objects for selects |
values() |
All values |
names() |
All case names |
hasValue(string or int $value) |
Whether the value exists |
When the label method is missing, labels fall back to a humanized case name.
Examples
Fill a select from the enum with the generated helpers:
import { OrderStatus, OrderStatusUtils } from '@/enums/order-status';
export function StatusSelect() {
return (
<select>
{OrderStatusUtils.options().map((status) => (
<option key={status} value={status}>
{OrderStatusUtils.label(status)}
</option>
))}
</select>
);
}Pass options from a controller using the trait:
use App\Enums\OrderStatus;
use DevWizardHQ\Enumify\Concerns\EnumHelpers;
enum OrderStatus: string
{
use EnumHelpers;
case PENDING = 'pending';
case SHIPPED = 'shipped';
}
OrderStatus::selectOptions();Translate labels in React. Install Laravel Localizer React, set the mode and sync again:
'localization' => [
'mode' => 'react',
],import { useOrderStatusUtils } from '@/enums/order-status';
const { label, options } = useOrderStatusUtils();Preview, then apply, a refactor with backups:
php artisan enumify:refactor --dry-run
php artisan enumify:refactor --fix --backupFAQ & Troubleshooting
No files are generated. Check that your enums live under paths.enums and are not removed by filters.include or filters.exclude. Run php artisan enumify:sync --dry-run to see what is discovered.
Imports fail during the frontend build. Confirm the output folder exists, with enumify:install if needed, and that the Vite plugin is enabled and listed before the Laravel plugin.
A method is missing from the generated file. Only public, non-static methods with no arguments and a scalar return type are converted. Methods without a return type are skipped.
Should generated files be committed? The installer suggests gitignoring them and keeping the .gitkeep. Since the plugin regenerates them on every build, that works for most teams. Commit them if your build environment has no PHP.
What does the refactor command not touch? Columns without an enum cast on a model, and any path in refactor.exclude. Use --dry-run or --backup first.
Why do I get a localization hook instead of an object? localization.mode is react or vue. Set it to none for a static Utils object.
Changelog & Support
Release history is in the CHANGELOG and on the GitHub releases page. Report bugs and request features in GitHub issues. Source: DevWizardHQ/laravel-enumify. Pair it with Vite plugin Enumify. For help with Laravel and Inertia products, the DevWizard team takes project contracts and monthly retainers through the contact page.