webworkerjoshua / laravel-nanoid
A Laravel package for generating and managing Nano ID values.
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.22
- orchestra/testbench: ^9.0|^10.0|^11.0
- phpunit/phpunit: ^10.5|^11.0|^12.0
README
webworkerJoshua/laravel-nanoid is a Laravel package for generating and assigning Nano ID values.
The generator follows the secure API from Nano ID 5 where it maps cleanly to PHP:
- secure random bytes from
random_bytes() - the official URL-friendly
urlAlphabet - default size of 21 characters
- custom alphabets with rejection sampling to avoid modulo bias
- custom random byte generators for tests or advanced integrations
The JavaScript package also ships a non-secure API based on Math.random(). This package intentionally exposes only the secure generator.
References:
- Official collision calculator: https://zelark.github.io/nano-id-cc/
- Official Nano ID repository: https://github.com/ai/nanoid
Installation
Requirements:
- PHP 8.2+
- Laravel 11, 12, or 13
composer require webworkerjoshua/laravel-nanoid
Publish the config when you want to change defaults:
php artisan vendor:publish --tag=nanoid-config
Usage
use WebworkerJoshua\LaravelNanoid\Facades\Nanoid; $id = Nanoid::generate(); $shortId = Nanoid::generate(10);
The package also provides a helper:
$id = nanoid();
For custom alphabets:
use WebworkerJoshua\LaravelNanoid\Nanoid; $generator = new Nanoid; $hex = $generator->customAlphabet('0123456789abcdef', 10); $id = $hex(); $shortId = $hex(5);
For a custom random byte source:
use WebworkerJoshua\LaravelNanoid\Nanoid; $generator = new Nanoid; $custom = $generator->customRandom( alphabet: 'abcdef', defaultSize: 10, random: fn (int $bytes): string => random_bytes($bytes), ); $id = $custom();
The random callback must accept the requested byte count and return either a binary string or an iterable of integers from 0 to 255.
API Notes
Nanoid::generate()andnanoid()generate 21 characters by default.Nanoid::generate(0)returns an empty string.- ID sizes must be between 0 and 1024 characters.
- Custom alphabets must be non-empty and contain 256 symbols or less.
customAlphabet($alphabet, $size)returns a callable that also accepts a per-call size override.customRandom($alphabet, $size, $random)follows Nano ID's rejection-sampling algorithm to avoid modulo bias.
Eloquent
Add the HasNanoids trait to a model to fill the configured attribute when the model is created:
use Illuminate\Database\Eloquent\Model; use WebworkerJoshua\LaravelNanoid\Eloquent\HasNanoids; class Post extends Model { use HasNanoids; protected $fillable = [ 'title', ]; }
When the Nano ID attribute is the model key, the trait sets $incrementing = false and $keyType = 'string' during model initialization. Primary keys use a model prefix by default, so a User model receives IDs like user_V1StGXR8_Z5jdHi6B-myT.
Use a string column long enough for the prefix plus the generated ID, and add a unique index for non-primary Nano ID columns:
Schema::create('posts', function (Blueprint $table): void { $table->string('id', 64)->primary(); $table->string('public_id', 64)->unique()->nullable(); $table->string('title'); $table->timestamps(); });
Models can override the attribute, size, alphabet, or prefix:
class Post extends Model { use HasNanoids; protected $fillable = [ 'title', ]; protected string $nanoidAttribute = 'public_id'; protected int $nanoidSize = 10; protected string $nanoidAlphabet = '0123456789abcdef'; protected string $nanoidPrefix = 'post_'; }
You can generate Nano IDs for multiple columns and configure each column independently:
class Session extends Model { use HasNanoids; protected $fillable = [ 'name', ]; protected array $nanoidAttributes = ['id', 'user_id']; protected array $nanoidPrefix = [ 'id' => 'session_', 'user_id' => 'user_', ]; protected array $nanoidSize = [ 'id' => 21, 'user_id' => 12, ]; protected array $nanoidAlphabet = [ 'user_id' => '0123456789abcdef', ]; }
Each per-column option may also define a '*' fallback key.
Existing attribute values are preserved. The trait does not query the database to retry collisions; enforce uniqueness with primary or unique indexes.
Configuration
return [ 'alphabet' => env('NANOID_ALPHABET', Nanoid::DEFAULT_ALPHABET), 'size' => (int) env('NANOID_SIZE', Nanoid::DEFAULT_SIZE), 'prefix' => env('NANOID_PREFIX'), 'use_model_prefix' => filter_var(env('NANOID_USE_MODEL_PREFIX', true), FILTER_VALIDATE_BOOLEAN), 'model_attribute' => env('NANOID_MODEL_ATTRIBUTE', 'id'), ];
Use the official collision calculator before reducing size or alphabet length for high-volume IDs.
Available environment variables:
NANOID_ALPHABETNANOID_SIZENANOID_PREFIXNANOID_USE_MODEL_PREFIXNANOID_MODEL_ATTRIBUTE
Testing
composer test
composer larastan
composer format