How to Create a Custom Artisan Command in Laravel

Laravel Artisan is Laravel's built-in command-line interface (CLI) and it's very powerful. Besides the hundreds of built-in commands like php artisan migrate or php artisan make:mo...

How to Create a Custom Artisan Command in Laravel

Laravel Artisan is Laravel's built-in command-line interface (CLI) and it's very powerful. Besides the hundreds of built-in commands like php artisan migrate or php artisan make:model, you can also create your own commands. Custom Artisan commands are very useful for automating routine tasks such as cleaning up old data, sending daily reports, or syncing data from an external API.

Creating a New Command

Use Artisan to generate a new command skeleton:

php artisan make:command SendDailyReport

The file is created at app/Console/Commands/SendDailyReport.php. Laravel 11 automatically discovers commands in this folder, so no manual registration is needed.

The Anatomy of a Laravel Command

Open the newly created file and understand its structure:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class SendDailyReport extends Command
{
    // Signature: the command name and its arguments/options
    protected $signature = 'report:daily
                            {type : Report type (sales/inventory)}
                            {--email= : Destination email address}
                            {--dry-run : Run without actually sending the email}';

    // Description shown in php artisan list
    protected $description = 'Send a daily report to the admin via email';

    // Main command logic
    public function handle(): int
    {
        $type    = $this->argument('type');
        $email   = $this->option('email') ?? 'admin@example.com';
        $dryRun  = $this->option('dry-run');

        $this->info("Preparing report of type: {$type}");

        if (! in_array($type, ['sales', 'inventory'])) {
            $this->error("Invalid report type. Use 'sales' or 'inventory'.");
            return Command::FAILURE;
        }

        // Simulate generating the report
        $this->withProgressBar(range(1, 5), function ($step) {
            sleep(1); // Simulate a process
        });

        $this->newLine();

        if ($dryRun) {
            $this->warn("Dry-run mode: email not sent to {$email}");
        } else {
            $this->info("The {$type} report was sent successfully to: {$email}");
            // Here you would call a Mailable or Notification
        }

        return Command::SUCCESS;
    }
}

Arguments and Options in the Signature

The signature format follows these rules:

  • {name} — required argument.
  • {name?} — optional argument.
  • {name=default} — argument with a default value.
  • {--option} — boolean flag (present/absent).
  • {--option=} — option with a string value.
  • {--option=default} — option with a default value.

Running the Command

# Required argument
php artisan report:daily sales

# With an option
php artisan report:daily inventory --email=budi@example.com

# With the dry-run flag
php artisan report:daily sales --dry-run

Interacting with the User

Laravel commands provide various methods for interacting with the user in the terminal:

public function handle(): int
{
    // Ask for confirmation
    if (! $this->confirm('Are you sure you want to delete old data?')) {
        $this->line('Operation cancelled.');
        return Command::SUCCESS;
    }

    // Ask for input from the user
    $name = $this->ask('Enter the report name:');

    // Choice from a list
    $format = $this->choice('Output format:', ['PDF', 'Excel', 'CSV'], 0);

    // Ask for a password (hidden)
    $secret = $this->secret('Enter the API key:');

    // Colored output
    $this->info('Info (green)');
    $this->warn('Warning (yellow)');
    $this->error('Error (red)');

    // Display a table
    $this->table(
        ['ID', 'Name', 'Email'],
        User::select('id', 'name', 'email')->limit(5)->get()->toArray()
    );

    return Command::SUCCESS;
}

Real Example: A Command to Delete Old Data

<?php

namespace App\Console\Commands;

use App\Models\Log;
use Illuminate\Console\Command;

class PruneOldLogs extends Command
{
    protected $signature = 'logs:prune {--days=30 : Delete logs older than N days}';
    protected $description = 'Delete old logs from the database';

    public function handle(): int
    {
        $days    = (int) $this->option('days');
        $cutoff  = now()->subDays($days);

        $count = Log::where('created_at', '<', $cutoff)->count();

        if ($count === 0) {
            $this->info('No old logs to delete.');
            return Command::SUCCESS;
        }

        if ($this->confirm("This will delete {$count} logs before {$cutoff->toDateString()}. Continue?")) {
            Log::where('created_at', '<', $cutoff)->delete();
            $this->info("{$count} logs deleted successfully.");
        }

        return Command::SUCCESS;
    }
}

Scheduling a Command with the Scheduler

To run a command automatically on a schedule, register it in routes/console.php (Laravel 11) or app/Console/Kernel.php (Laravel 10):

// Laravel 11 — routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('report:daily sales --email=admin@site.com')->dailyAt('07:00');
Schedule::command('logs:prune --days=30')->weekly();

// Add a cron entry on the server:
// * * * * * cd /path-to-project && php artisan schedule:run >> /dev/null 2>&1

Conclusion

Creating a custom Artisan command in Laravel is the best way to automate routine tasks that don't need to be done manually. With arguments, options, rich terminal interaction, and scheduler integration, Laravel commands can become the backbone of your application's background processes. From simple commands like clearing the cache to complex ones like generating PDF reports — it can all be done elegantly with Artisan.

artisan command laravel custom artisan command laravel console command laravel schedule artisan membuat command laravel php artisan custom
Share this article
Back to Blog
🚀 Partner Recommendation

Need Premium Source Code & Business Apps?

Access Laravel applications, POS systems, School Management, Clinic Software, ERP solutions, and ready-to-use premium source code at GudangCode.

GudangCode
  • ✔ Premium Source Code
  • ✔ Ready-to-Use Systems
  • ✔ Lifetime Updates
  • ✔ Lifetime Membership
  • ✔ Daily App Updates
Join Membership →