---
title: "Quick start — Sluggable for Laravel | Roundly"
description: "Add the HasSlug trait and the Sluggable contract — with zero config, a unique slug is generated from name on create."
url: https://roundly-consulting.com/open-source/docs/sluggable-for-laravel/quick-start
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Sluggable for Laravel](https://roundly-consulting.com/open-source/docs/sluggable-for-laravel.md)

# Quick start

Add the Sluggable contract and the HasSlug trait to a model. With no further configuration, a slug column is generated from the name attribute on create, and collisions get a sequential suffix:

```php
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Sluggable\Concerns\HasSlug;
use RoundlyConsulting\Sluggable\Contracts\Sluggable;

final class Clinic extends Model implements Sluggable
{
    use HasSlug;   // zero config: `slug` generated from `name`

    protected $fillable = ['name', 'slug'];
}

Clinic::create(['name' => 'Happy Paws'])->slug;   // "happy-paws"
Clinic::create(['name' => 'Happy Paws'])->slug;   // "happy-paws-2"
```

Both are required: using the trait without implements Sluggable throws InvalidSlugDefinitionException (missingContract). The zero-config column and source come from sluggable.defaults.column and sluggable.defaults.source.

## The migration

Two Blueprint macros add the column and a unique index matching the default definition (global uniqueness, trashed rows count as taken):

```php
Schema::create('clinics', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->slug();          // string('slug', 255)
    $table->uniqueSlug();    // unique index clinics_slug_slug_unique
    $table->timestamps();
});
```

## Reading the slug

Besides the attribute itself, the contract gives every sluggable model readers that matter most for locale maps but work on string columns too:

```php
$clinic->slug;            // "happy-paws"
$clinic->currentSlug();   // "happy-paws"
$clinic->slugMap();       // ['*' => 'happy-paws']  (Sluggable::SINGLE_KEY)
```

slugFor($locale) reads one exact locale and is for locale-map columns only — on a string column it throws. Every reader takes an optional column name; null means the routeKey() column, else the first definition.

With the default options the generated value matches Str::slug() for ordinary input of up to 255 characters, so adding the trait to an existing model keeps the slugs you already have. The differences are covered under Formatting & suffixes.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/sluggable-for-laravel.md)
