461 words, 3 min read

Sooner or later, every codebase has a command whose name you can't remember. Say you have reports:generate-monthly. Half the team types reports:monthly from muscle memory and gets "Command not defined". You don't want to rename the command because runbooks, scripts, and Slack history all reference the old name. So you give it a second name.

The short version

Aliases are a Symfony Console feature, and Artisan is built on Symfony Console. Laravel supports them in three ways.

1. The $aliases property

class GenerateMonthlyReportCommand extends Command
{
    protected $signature = 'reports:generate-monthly {reportId}';

    protected $description = 'Generates the monthly report for the given id';

    protected $aliases = ['reports:monthly'];
}

Laravel's Command constructor reads this property and calls Symfony's setAliases() for you. This is the approach we use.

2. The #[Aliases] attribute

Laravel 13 also has class attributes for command metadata:

use Illuminate\Console\Attributes\Aliases;

#[Aliases(['reports:monthly'])]
class GenerateMonthlyReportCommand extends Command
{
    // ...
}

The #[Signature] attribute also accepts an aliases argument, so the signature and its aliases can sit together. Use whichever style your commands already use.

3. Overriding configure()

protected function configure(): void
{
    parent::configure();

    $this->setAliases(['reports:monthly']);
}

This works on any Laravel version because it uses plain Symfony. On recent versions, you rarely need it.

What you get

Both names run the same command with the same arguments and options:

php artisan reports:generate-monthly 123
php artisan reports:monthly 123

php artisan list shows the alias as its own entry and marks the canonical command with the alias in brackets, so people can see that the two names belong together:

reports:monthly            Generates the monthly report for the given id
reports:generate-monthly   [reports:monthly] Generates the monthly report for the given id

Gotchas

  • An alias is only a name. Don't put arguments or options in it. The signature ({reportId}) belongs to the command and is shared by every name. If you write 'reports:monthly {reportId}' as an alias, Symfony takes the whole string as the name, including the placeholder.
  • Aliases must be unique. Run php artisan list after adding one to check that it doesn't collide with another command.
  • Scheduling and queues. Schedule::command('reports:monthly'), $this->call(), and Artisan::call() all resolve aliases. Still, use the canonical name in code so a grep for the command finds every use.
  • Decide which name is canonical. The alias is a convenience. If you want people to move to the new name, make it the $signature name and keep the old one as the alias. That gives you a painless rename.
  • Test it. Run the command through its alias once in a test so a typo in the alias doesn't go unnoticed.