Skip to content

Referenceable: Generate Clean and Customizable Reference Numbers in Laravel

Referenceable is an open-source Laravel package for generating clean, customizable reference numbers for Eloquent models using random, sequential, or template-based strategies, with support for sequence resets, multi-tenancy, validation, and collision handling.

Published · Updated · 8 min read

Referenceable: Generate Clean and Customizable Reference Numbers in Laravel

Referenceable: A Better Way to Generate Reference Numbers in Laravel

Almost every business application eventually needs human-friendly reference numbers.

An order might need:

ORD-2026-0001

An invoice might use:

INV-001024

A support ticket could look like:

TKT-X7K92P

At first, generating these values seems simple.

Add a column, generate a random string or increment a number, save it, and move on.

But as the application grows, the requirements usually grow with it.

You may need different formats for different models, yearly or monthly sequence resets, tenant-specific numbering, validation, collision handling, custom prefixes, or references that contain dates and other dynamic values.

That is exactly the problem I wanted to solve when I created Referenceable.

Referenceable is an open-source Laravel package for generating flexible, customizable, and reliable reference numbers for Eloquent models.

GitHub:

https://github.com/EG-Mohamed/Referenceable


The Problem With Reference Numbers

Database IDs are excellent for databases:

1
2
3
18492

But they are usually not great identifiers to expose to customers or employees.

Imagine receiving this confirmation:

Your order number is #18374

Now compare it with:

Your order number is ORD-2026-018374

The second version immediately provides more context and feels much more appropriate for a production business application.

You can certainly implement this yourself.

The problem is that reference generation quickly becomes repetitive.

You start with something like:

$order->reference = 'ORD-' . Str::random(8);

Then requirements start arriving:

  • References must be unique.
  • Invoice numbers should be sequential.
  • Sequences should restart every year.
  • Orders need a different format.
  • Some references need the current month.
  • Characters such as 0, O, 1, and I should be excluded.
  • Each organization should have its own sequence.
  • Existing records need references.
  • Generated references need validation.

At this point, something that originally looked like a few lines of code has become its own subsystem.

Referenceable moves that responsibility into a reusable package.


Meet Referenceable

Referenceable provides three main strategies for generating model references:

1. Random References

Perfect when the sequence itself is not important.

For example:

ORD-AB12CD
TKT-X7K92P
USR-M4NP8Q

You can configure the prefix, length, allowed characters, excluded characters, letter case, separator, and more.

For example:

protected $referenceStrategy = 'random';
protected $referencePrefix = 'ORD';
protected $referenceLength = 6;
protected $referenceCase = 'upper';

Which can generate something like:

ORD-AB12CD

2. Sequential References

For invoices, purchase orders, quotations, or other records where sequential numbering makes more sense, Referenceable can automatically manage the counter.

For example:

protected $referenceStrategy = 'sequential';
protected $referencePrefix = 'INV';

protected $referenceSequential = [
    'start' => 1000,
    'min_digits' => 6,
    'reset_frequency' => 'yearly',
];

This can produce:

INV-001000
INV-001001
INV-001002

Sequences can be configured to reset:

Never
Daily
Monthly
Yearly

This makes the strategy useful for many accounting, ERP, CRM, booking, ticketing, and internal business systems.


3. Template-Based References

This is probably my favorite part of the package.

Instead of being restricted to one predefined structure, you can define your own reference template.

For example:

protected $referenceStrategy = 'template';

protected $referenceTemplate = [
    'format' => '{PREFIX}{YEAR}{MONTH}{SEQ}',
    'sequence_length' => 4,
];

protected $referencePrefix = 'ORD';

This allows references such as:

ORD2026090001
ORD2026090002
ORD2026090003

Referenceable supports placeholders including:

{PREFIX}
{SUFFIX}
{YEAR}
{YEAR2}
{MONTH}
{DAY}
{SEQ}
{RANDOM}
{MODEL}
{TIMESTAMP}

This means you can create structures such as:

ORD-2026-09-0001

or:

INV-26-000001

or even:

TICKET-202609-X7K9

without rebuilding your reference-generation logic every time.


Getting Started

Installation is straightforward.

Install the package using Composer:

composer require eg-mohamed/referenceable

Then run:

php artisan referenceable:install

The installation command prepares the package configuration and required database structures.

Next, add a reference column to your model's table:

Schema::create('orders', function (Blueprint $table) {
    $table->id();

    $table->string('reference')
        ->unique()
        ->index();

    $table->timestamps();
});

Then add the HasReference trait to your model:

use MohamedSaid\Referenceable\Traits\HasReference;

class Order extends Model
{
    use HasReference;
}

That's basically it.

Now when you create an order:

$order = Order::create([
    'customer_id' => 1,
    'total' => 99.99,
]);

Referenceable can automatically assign its reference:

echo $order->reference;

For example:

AB12CD34

From there, you can customize the generation behavior for each model.


Model-Level Configuration

One important goal while building Referenceable was avoiding a one-size-fits-all configuration.

Different models usually have different requirements.

An Invoice may need sequential references while an Order uses a template and a Ticket uses a random code.

Referenceable allows these settings to live directly on the model.

For example:

protected $referenceColumn = 'order_number';

protected $referenceStrategy = 'template';

protected $referencePrefix = 'ORD';

protected $referenceSeparator = '-';

protected $referenceTemplate = [
    'format' => '{PREFIX}{YEAR}{MONTH}{SEQ}',
    'sequence_length' => 4,
];

You still have global defaults available in:

config/referenceable.php

So applications can choose between global conventions and model-specific customization.


Multi-Tenant Applications

Multi-tenancy introduces another interesting problem.

Imagine an application containing multiple companies.

Company A may need:

INV-000001

while Company B should also be able to have:

INV-000001

The references are unique within the organization rather than globally.

Referenceable supports tenant-aware uniqueness:

class Order extends Model
{
    use HasReference;

    protected $referenceUniquenessScope = 'tenant';

    protected $referenceTenantColumn = 'company_id';
}

This makes the package particularly useful in SaaS applications where each tenant maintains its own numbering system.


Collision Handling and Validation

Random reference generation introduces another question:

What happens if the same reference is generated twice?

Referenceable includes collision detection and configurable collision strategies.

For example:

protected $referenceCollisionStrategy = 'retry';
protected $referenceMaxRetries = 100;

References can also be validated using configurable rules, lengths, and regular expressions.

For example:

protected $referenceValidation = [
    'pattern' => '/^ORD-\d{4}-\w{6}$/',
    'min_length' => 8,
    'max_length' => 20,
];

This keeps reference generation predictable instead of relying on application code scattered across controllers, observers, services, and models.


Working With References

Referenceable also provides useful APIs for working with generated references.

Generate one manually:

$reference = $order->generateReference();

Regenerate an existing reference:

$order->regenerateReference(save: true);

Check whether a model already has one:

if ($order->hasReference()) {
    // ...
}

Validate it:

$order->validateReference();

And find a model directly using its reference:

$order = Order::findByReference('ORD-123456');

There are also query scopes for filtering models with or without references and filtering by reference prefixes.


Artisan Commands

Another requirement I wanted to cover was maintaining references after an application was already running.

Referenceable therefore provides several Artisan commands.

Generate missing references:

php artisan referenceable:generate "App\Models\Order"

Preview the operation first:

php artisan referenceable:generate "App\Models\Order" --dry-run

Validate existing references:

php artisan referenceable:validate "App\Models\Order"

View reference statistics:

php artisan referenceable:stats "App\Models\Order"

And regenerate references when necessary:

php artisan referenceable:regenerate "App\Models\Order" --id=123

This becomes particularly useful when introducing Referenceable into an existing application containing thousands or millions of records.


Where Can Referenceable Be Used?

Reference numbers appear in almost every type of business software.

Some common examples include:

E-commerce

ORD-2026-000154

Invoices

INV-000248

Support tickets

TKT-X72K91

Bookings

BKG-202609-0042

Purchase orders

PO-26-000145

Shipments

SHP-A7DK92

CRM opportunities

LEAD-2026-0182

Event registrations

REG-2026-X82LQ

The goal isn't to decide what your reference numbers should look like.

The goal is to give you enough flexibility to define that yourself.


Built for Real Laravel Applications

Referenceable currently supports Laravel 10 through Laravel 13 and includes functionality for:

  • Random reference generation
  • Sequential numbering
  • Template-based generation
  • Daily, monthly, and yearly sequence resets
  • Configurable prefixes and suffixes
  • Custom separators
  • Custom character sets
  • Excluded characters
  • Reference validation
  • Uniqueness checking
  • Automatic collision handling
  • Multi-tenant reference generation
  • Batch operations
  • Artisan management commands
  • Configuration caching
  • Database transactions

The package is open source and released under the MIT license.


Why I Built It

A lot of open-source packages start with the same thought:

"I've implemented this too many times."

Reference generation was one of those things for me.

Across different systems, I kept encountering slightly different versions of the same requirement.

Orders needed references.

Invoices needed references.

Tickets needed references.

Registrations needed references.

And every project had slightly different rules.

Instead of continuing to rebuild the same concept, I wanted a reusable implementation that could handle simple requirements while still being flexible enough for more complex applications.

That became Referenceable.


Try Referenceable

If you're building a Laravel application and find yourself writing custom logic for order numbers, invoice numbers, tickets, bookings, registrations, or other business identifiers, give Referenceable a try.

Install it with:

composer require eg-mohamed/referenceable

You can find the source code, documentation, examples, issues, and contribution guidelines on GitHub:

https://github.com/EG-Mohamed/Referenceable

If the package saves you some development time, consider giving the repository a ⭐.

And because it's open source, contributions, bug reports, ideas, and feature requests are always welcome.

Happy coding! 🚀

Mohamed Said

About the author

Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

About GitHub LinkedIn WhatsApp Email Address My CV

Have a technical challenge?

Tell me what you’re building. I reply within two working days.

Discuss your project