# Laravel Prefixed IDs Laravel Prefixed IDs is a package by Spatie that generates friendly, human-recognizable prefixed identifiers for Laravel Eloquent models. Inspired by Stripe's ID format (e.g., `cus_abc123`, `sk_live_xyz`), this package automatically creates unique IDs with custom prefixes that help users and developers instantly identify the type of resource they're working with. The package provides a simple trait-based approach for adding prefixed IDs to your models, along with helper methods for finding models by their prefixed ID across different model types. It integrates seamlessly with Laravel's Eloquent ORM and supports customizable ID generation, making it ideal for APIs, webhooks, and any scenario where readable, type-identifiable IDs improve developer experience. ## Installation Install the package via Composer. ```bash composer require spatie/laravel-prefixed-ids ``` ## Database Migration Add a `prefixed_id` column to your model's table. ```php string('prefixed_id')->nullable()->unique(); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('prefixed_id'); }); } } ``` ## HasPrefixedId Trait Add the `HasPrefixedId` trait to your Eloquent model to enable automatic prefixed ID generation when creating new records. ```php User::class, 'order_' => Order::class, 'prod_' => Product::class, ]); } } // Now when you create models, they automatically get prefixed IDs: $user = User::create(['name' => 'John Doe', 'email' => 'john@example.com']); echo $user->prefixed_id; // Output: user_550e8400e29b41d4a716446655440000 $order = Order::create(['total' => 99.99]); echo $order->prefixed_id; // Output: order_6ba7b8109dad11d180b400c04fd430c8 $product = Product::create(['name' => 'Widget']); echo $product->prefixed_id; // Output: prod_f47ac10b58cc4372a5670e02b2c3d479 ``` ## Model::findByPrefixedId() Find a specific model instance by its prefixed ID. Returns the model or `null` if not found. ```php name}"; } else { echo "User not found"; } // Returns null for non-existing IDs $notFound = User::findByPrefixedId('user_nonexistent'); var_dump($notFound); // Output: NULL ``` ## Model::findByPrefixedIdOrFail() Find a model by its prefixed ID or throw a `NoPrefixedModelFound` exception if not found. Useful for controller actions where you want to return a 404 response. ```php json([ 'id' => $user->prefixed_id, 'name' => $user->name, 'email' => $user->email, ]); } catch (NoPrefixedModelFound $e) { return response()->json([ 'error' => 'User not found', 'message' => $e->getMessage(), ], 404); } } } // Usage: // GET /api/users/user_550e8400e29b41d4a716446655440000 // Response: {"id": "user_550e8400...", "name": "John Doe", "email": "john@example.com"} // GET /api/users/user_invalid // Response: {"error": "User not found", "message": "Could not find a prefixed model `user_invalid`"} ``` ## PrefixedIds::find() Find any model across all registered model types by its prefixed ID. The method automatically determines the correct model class based on the prefix. ```php json([ 'type' => class_basename($model), 'id' => $model->prefixed_id, 'data' => $model->toArray(), ]); } catch (NoPrefixedModelFound $e) { return response()->json([ 'error' => 'Resource not found', ], 404); } } } // Works with any registered model type: // GET /api/resources/user_abc123 -> Returns User data // GET /api/resources/order_xyz789 -> Returns Order data // GET /api/resources/invalid_id -> Returns 404 ``` ## PrefixedIds::getModelClass() Get the model class name for a given prefixed ID without fetching the model from the database. Useful for validation or routing logic. ```php resource_id); if ($modelClass === User::class) { return ['action' => 'required|in:activate,deactivate']; } if ($modelClass === Order::class) { return ['action' => 'required|in:ship,cancel,refund']; } throw new ValidationException('Unknown resource type'); } } ``` ## PrefixedIds::generateUniqueIdUsing() Customize the unique ID generation algorithm. By default, the package uses UUID v4 (with dashes removed). You can provide your own generator for shorter IDs, sequential IDs, or any custom format. ```php 'Jane']); echo $user->prefixed_id; // Output: user_a1b2c3d4 // Use Laravel's Str helper for a different format PrefixedIds::generateUniqueIdUsing(function () { return Str::random(12); }); $order = Order::create(['total' => 50.00]); echo $order->prefixed_id; // Output: order_Xk9mP2nQ4rT1 // Use ULID for sortable IDs PrefixedIds::generateUniqueIdUsing(function () { return strtolower((string) Str::ulid()); }); $product = Product::create(['name' => 'Gadget']); echo $product->prefixed_id; // Output: prod_01aryz6s41tsp2m3xqjvwy // Reset to default UUID generation PrefixedIds::generateUniqueIdUsing(null); ``` ## Route Model Binding Use prefixed IDs in your Laravel routes by implementing the `getRouteKeyName` method on your model. ```php json([ 'id' => $user->prefixed_id, 'name' => $user->name, ]); }); // Now you can access users by their prefixed ID: // GET /api/users/user_550e8400e29b41d4a716446655440000 // Response: {"id": "user_550e8400...", "name": "John Doe"} ``` ## Configuration Publish and customize the configuration file to change the attribute name used for storing prefixed IDs. ```bash php artisan vendor:publish --provider="Spatie\PrefixedIds\PrefixedIdsServiceProvider" --tag="prefixed-ids-config" ``` ```php 'prefixed_id', // Example: use 'public_id' instead // 'prefixed_id_attribute_name' => 'public_id', ]; // If you change the attribute name, update your migration accordingly: Schema::table('users', function (Blueprint $table) { $table->string('public_id')->nullable()->unique(); }); // And access it via the new attribute: $user = User::create(['name' => 'John']); echo $user->public_id; // Output: user_550e8400... ``` ## Summary Laravel Prefixed IDs is ideal for building APIs where human-readable, type-identifiable IDs improve developer experience. Common use cases include exposing public-facing IDs in REST APIs (instead of auto-incrementing integers), handling webhooks that reference multiple resource types, building admin interfaces where resource types need to be quickly identified, and creating shareable URLs that remain meaningful to users. The package integrates smoothly with Laravel's existing patterns including route model binding, Eloquent relationships, and service providers. For best results, register all your prefixed models in a service provider's `boot` method, use the `PrefixedIds::find()` method for polymorphic lookups in webhook handlers, and consider customizing the ID generator for shorter, more URL-friendly identifiers. The package works with Laravel 11, 12, and 13, requiring PHP 8.2 or higher.