Documentation Index
Fetch the complete documentation index at: https://kawax.biz/llms.txt
Use this file to discover all available pages before exploring further.
What is Artisan?
Artisan is the command-line interface bundled with Laravel. It lives at the project root as the artisan script and provides dozens of commands to help you build and maintain your application.
List all available commands:
Get help for a specific command:
If you use Laravel Sail, replace php artisan with sail artisan. Commands run inside the Docker container../vendor/bin/sail artisan list
Tinker (REPL)
Laravel Tinker is an interactive REPL that lets you interact with your application directly from the terminal—query Eloquent models, dispatch jobs, fire events, and more.
Once inside Tinker you can run any PHP code:
>>> App\Models\User::find(1)
>>> App\Models\User::factory()->create()
>>> app(App\Services\OrderService::class)->process(1)
Tinker writes to your real database. Limit its use to local or staging environments, and be careful on production.
Writing commands
Generating a command
Use make:command to scaffold a new command class in app/Console/Commands:
php artisan make:command SendWeeklyReport
Command structure
In Laravel 13, define the command signature and description with PHP attributes. The handle() method contains the logic:
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Support\DripEmailer;
use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
use Illuminate\Console\Command;
#[Signature('mail:send {user : The ID of the user to email}')]
#[Description('Send a marketing email to a user')]
class SendEmails extends Command
{
/**
* Execute the console command.
*/
public function handle(DripEmailer $drip): void
{
$drip->send(User::find($this->argument('user')));
}
}
You can also use the classic $signature and $description properties instead of attributes—both work in Laravel 13.protected $signature = 'mail:send {user}';
protected $description = 'Send a marketing email to a user';
Keep commands thin. Delegate the actual work to service classes so your logic stays reusable and testable.
Exit codes
A command exits with 0 (success) by default. Return an integer from handle() to set a custom exit code:
public function handle(): int
{
$this->error('Something went wrong.');
return 1;
}
Or call fail() to immediately terminate with exit code 1:
$this->fail('Something went wrong.');
Closure commands
Define lightweight commands directly in routes/console.php without a full class:
use Illuminate\Support\Facades\Artisan;
Artisan::command('inspire', function () {
$this->info(Inspiring::quote());
})->purpose('Display an inspiring quote');
Arguments and options
Define arguments and options in the $signature string (or #[Signature] attribute):
protected $signature = 'import:products
{file : Path to the CSV file}
{--limit= : Maximum number of rows to import}
{--dry-run : Preview without saving to the database}';
| Syntax | Type | Notes |
|---|
{file} | Required argument | Missing value causes an error |
{file?} | Optional argument | Defaults to null when omitted |
{file=products.csv} | Argument with default | Uses the default when omitted |
{--queue} | Flag option | true when passed, false otherwise |
{--limit=} | Value option | Passed as --limit=100 |
{--limit=50} | Option with default | Uses 50 when omitted |
{--Q|queue} | Option with shortcut | -Q is equivalent to --queue |
public function handle(): void
{
$file = $this->argument('file');
$limit = $this->option('limit');
$dryRun = $this->option('dry-run');
$this->info("Processing: {$file}");
if ($dryRun) {
$this->warn('Dry run — no data will be saved.');
}
}
Interacting with the user
Output methods
$this->info('Operation completed successfully.'); // Green
$this->warn('This cannot be undone.'); // Yellow
$this->error('An error occurred.'); // Red
$this->line('Plain text output.'); // No color
$this->comment('Additional context here.'); // Grey
// Free-text input
$name = $this->ask('Enter the operator name');
// Input with a default
$env = $this->ask('Select environment', 'production');
// Hidden input for secrets
$apiKey = $this->secret('Enter your API key');
// Yes / No confirmation
if (! $this->confirm('Import to the production database?')) {
$this->info('Cancelled.');
return;
}
// Select from a list
$format = $this->choice('Choose an output format', ['csv', 'json', 'xml'], 0);
Progress bars
Display progress for long-running operations:
use App\Models\Product;
// Automatic progress bar over a collection
$this->withProgressBar(Product::cursor(), function (Product $product) {
$this->processProduct($product);
});
Manual control for more flexibility:
$total = Product::count();
$bar = $this->output->createProgressBar($total);
$bar->start();
Product::cursor()->each(function (Product $product) use ($bar) {
$this->processProduct($product);
$bar->advance();
});
$bar->finish();
$this->newLine();
Practical example: data import command
Generate the command
php artisan make:command ImportProducts
Implement the command
<?php
namespace App\Console\Commands;
use App\Models\Product;
use Illuminate\Console\Command;
class ImportProducts extends Command
{
protected $signature = 'import:products
{file : Path to the CSV file}
{--limit= : Maximum rows to import}
{--dry-run : Preview without saving}';
protected $description = 'Import products from a CSV file';
public function handle(): void
{
$filePath = $this->argument('file');
$limit = $this->option('limit') ? (int) $this->option('limit') : null;
$dryRun = $this->option('dry-run');
if (! file_exists($filePath)) {
$this->error("File not found: {$filePath}");
return;
}
$handle = fopen($filePath, 'r');
$headers = fgetcsv($handle);
$rows = [];
while (($row = fgetcsv($handle)) !== false) {
$rows[] = array_combine($headers, $row);
if ($limit !== null && count($rows) >= $limit) {
break;
}
}
fclose($handle);
$count = 0;
$this->withProgressBar($rows, function (array $row) use ($dryRun, &$count) {
if (! $dryRun) {
Product::updateOrCreate(
['sku' => $row['sku']],
['name' => $row['name'], 'price' => $row['price']]
);
}
$count++;
});
$this->newLine();
if ($dryRun) {
$this->warn("{$count} rows found (dry run — nothing was saved).");
} else {
$this->info("Imported {$count} products successfully.");
}
}
}
Run the command
# Standard import
php artisan import:products storage/products.csv
# Limit the number of rows
php artisan import:products storage/products.csv --limit=100
# Preview without saving
php artisan import:products storage/products.csv --dry-run
Scheduling commands
Register commands in routes/console.php to run them on a schedule. See the Task scheduling guide for details.
use Illuminate\Support\Facades\Schedule;
// Every night at 02:00
Schedule::command('orders:prune --days=90')->dailyAt('2:00');
// Every Monday at 09:00
Schedule::command('import:products storage/weekly.csv')->weeklyOn(1, '9:00');
Testing commands
Use the artisan() testing helper to simulate running a command:
<?php
namespace Tests\Feature\Commands;
use App\Models\Order;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PruneOldOrdersTest extends TestCase
{
use RefreshDatabase;
public function test_it_deletes_old_completed_orders(): void
{
Order::factory()->create([
'status' => 'completed',
'created_at' => now()->subDays(100),
]);
Order::factory()->create([
'status' => 'completed',
'created_at' => now()->subDays(10),
]);
$this->artisan('orders:prune', ['--days' => 90])
->expectsConfirmation('Delete completed orders older than 90 days?', 'yes')
->expectsOutput('Deleted 1 order(s).')
->assertExitCode(0);
$this->assertDatabaseCount('orders', 1);
}
}
| Assertion method | Purpose |
|---|
expectsOutput('...') | Assert specific text appears in output |
expectsQuestion('?', 'answer') | Simulate ask() input |
expectsConfirmation('?', 'yes') | Simulate confirm() input |
expectsChoice('?', 'option') | Simulate choice() selection |
assertExitCode(0) | Assert the exit code (0 = success) |
assertFailed() | Assert a non-zero exit code |
Common commands
php artisan make:command CommandName # Scaffold a new command class
php artisan list # List all available commands
php artisan help command:name # Show usage for a command
php artisan tinker # Open the interactive REPL