본문 바로가기

Artisan CLI

업데이트됨

번역일: 2026년 9월 15일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 9월 15일
번역 갱신
2026년 9월 15일

Artisan CLI

소개

Artisan은 라라벨에 기본으로 내장된 커맨드라인 인터페이스입니다. 프로젝트 루트에 있는 artisan 스크립트를 통해 실행하며, 애플리케이션을 개발하는 동안 유용하게 사용할 수 있는 다양한 명령어를 제공합니다. 사용 가능한 모든 명령어 목록을 확인하려면 list 명령어를 실행하면 됩니다.

php artisan list

모든 명령어에는 해당 명령어가 받아들이는 인자와 옵션을 설명하는 "도움말" 화면이 포함되어 있습니다. 도움말 화면을 보려면 명령어 이름 앞에 help를 붙이면 됩니다.

php artisan help migrate

NOTE

로컬 개발 환경에 Laravel Sail을 사용 중이라면, Artisan 명령어를 실행할 때 sail 명령줄을 함께 사용해야 한다는 점을 잊지 마세요. Sail은 애플리케이션의 Docker 컨테이너 내부에서 Artisan 명령어를 실행합니다.

./vendor/bin/sail artisan list

Tinker (REPL)

Laravel Tinker는 PsySH 패키지를 기반으로 하는, 라라벨 프레임워크를 위한 강력한 REPL(대화형 셸)입니다.

설치

모든 라라벨 애플리케이션에는 기본적으로 Tinker가 포함되어 있습니다. 다만 이전에 애플리케이션에서 Tinker를 제거한 적이 있다면, Composer를 통해 다시 설치할 수 있습니다.

composer require laravel/tinker

NOTE

라라벨 애플리케이션과 상호작용할 때 핫 리로딩, 여러 줄 코드 편집, 자동완성 기능이 필요하신가요? Tinkerwell을 확인해 보세요!

사용법

Tinker를 사용하면 Eloquent 모델, Job, 이벤트 등을 포함한 라라벨 애플리케이션 전체를 명령줄에서 자유롭게 다룰 수 있습니다. Tinker 환경에 진입하려면 tinker Artisan 명령어를 실행하세요.

php artisan tinker

Tinker 세션의 설정 파일을 게시하려면 vendor:publish 명령어를 사용합니다.

php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"

WARNING

Illuminate\Support\Facades\Schedule 클래스의 dispatch 헬퍼 함수는 큐에 등록된 Job을 디스패치하기 위해 사용하는 dispatch 함수와 충돌합니다. Tinker 안에서 이 충돌을 피하려면 dispatch 대신 Bus::dispatch 또는 Queue::push를 사용하세요.

명령어 허용 목록

Tinker는 셸 안에서 실행할 수 있는 Artisan 명령어를 제어하기 위해 "허용 목록(allow list)"을 사용합니다. 기본적으로 clear-compiled, down, env, inspire, migrate, optimize, up 명령어를 실행할 수 있습니다. 더 많은 명령어를 허용하고 싶다면, tinker.php 설정 파일의 commands 배열에 명령어 클래스를 추가하면 됩니다.

'commands' => [ // App\Console\Commands\ExampleCommand::class, ],

별칭(alias)이 지정되지 않아야 하는 클래스

일반적으로 Tinker는 상호작용하는 클래스에 자동으로 별칭을 부여합니다. 하지만 특정 클래스는 별칭을 지정하고 싶지 않을 수 있습니다. 이런 클래스는 tinker.php 설정 파일의 dont_alias 배열에 나열하여 별칭 대상에서 제외할 수 있습니다.

'dont_alias' => [ App\Models\User::class, ],

Artisan CLI

소개

Artisan은 Laravel에 기본으로 포함된 커맨드 라인 인터페이스(CLI)입니다. 애플리케이션 루트에 위치한 artisan 스크립트로 실행하며, 애플리케이션을 개발하는 동안 유용하게 쓸 수 있는 다양한 명령어를 제공합니다. 사용 가능한 모든 Artisan 명령어 목록을 확인하려면 list 명령어를 실행해 보세요:

php artisan list

모든 명령어는 사용 가능한 인수(argument)와 옵션(option)을 설명해주는 "도움말" 화면을 함께 제공합니다. 도움말을 보려면 명령어 이름 앞에 help를 붙이면 됩니다:

php artisan help migrate

Laravel Sail

로컬 개발 환경으로 Laravel Sail을 사용 중이라면, Artisan 명령어를 실행할 때 sail 커맨드 라인을 사용해야 한다는 점을 기억하세요. Sail은 애플리케이션의 Docker 컨테이너 내부에서 Artisan 명령어를 실행합니다:

./vendor/bin/sail artisan list

Tinker (REPL)

Laravel TinkerPsySH 패키지를 기반으로 만들어진, Laravel 프레임워크를 위한 강력한 REPL(대화형 셸)입니다.

설치

모든 Laravel 애플리케이션에는 Tinker가 기본으로 포함되어 있습니다. 만약 이전에 애플리케이션에서 Tinker를 제거한 적이 있다면, Composer로 다시 설치할 수 있습니다:

composer require laravel/tinker

NOTE

Laravel 애플리케이션과 상호작용할 때 핫 리로딩, 여러 줄 코드 편집, 자동완성 기능이 필요하신가요? Tinkerwell을 확인해 보세요!

사용법

Tinker를 사용하면 Eloquent 모델, Job, 이벤트 등 Laravel 애플리케이션 전체를 커맨드 라인에서 자유롭게 다룰 수 있습니다. Tinker 환경에 진입하려면 tinker Artisan 명령어를 실행하세요:

php artisan tinker

vendor:publish 명령어로 Tinker의 설정 파일을 게시(publish)할 수도 있습니다:

php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"

WARNING

dispatch 헬퍼 함수와 Dispatchable 클래스의 dispatch 메서드는 Job을 큐에 등록할 때 가비지 컬렉션(garbage collection)에 의존합니다. 따라서 Tinker 환경에서는 Bus::dispatchQueue::push를 사용해서 Job을 디스패치해야 합니다.

허용 명령어 목록(Command Allow List)

Tinker는 셸 안에서 실행 가능한 Artisan 명령어를 제한하기 위해 "허용 목록(allow list)"을 사용합니다. 기본적으로 clear-compiled, down, env, inspire, migrate, migrate:install, up, optimize 명령어만 실행할 수 있습니다. 더 많은 명령어를 허용하고 싶다면, tinker.php 설정 파일의 commands 배열에 추가하면 됩니다:

'commands' => [ // App\Console\Commands\ExampleCommand::class, ],

별칭(alias)을 적용하지 않을 클래스

Tinker는 기본적으로 여러분이 상호작용하는 클래스를 자동으로 별칭 처리합니다. 하지만 특정 클래스는 별칭 처리를 원하지 않을 수도 있습니다. 이런 경우 tinker.php 설정 파일의 dont_alias 배열에 해당 클래스를 나열하면 됩니다:

'dont_alias' => [ App\Models\User::class, ],

Artisan CLI

커맨드 작성하기

Artisan이 기본으로 제공하는 커맨드 외에도, 여러분만의 커스텀 커맨드를 직접 만들 수 있습니다. 커맨드는 보통 app/Console/Commands 디렉터리에 저장하지만, Artisan 커맨드를 스캔할 다른 디렉터리를 등록하기만 하면 원하는 위치에 자유롭게 저장할 수 있습니다.

커맨드 생성하기

새 커맨드를 만들려면 make:command Artisan 커맨드를 사용하면 됩니다. 이 커맨드는 app/Console/Commands 디렉터리에 새로운 커맨드 클래스를 생성합니다. 애플리케이션에 아직 이 디렉터리가 없더라도 걱정하지 마세요. make:command를 처음 실행할 때 자동으로 생성됩니다.

php artisan make:command SendEmails

커맨드 구조

커맨드를 생성한 후에는 SignatureDescription 속성(attribute)을 사용해 커맨드의 시그니처와 설명을 정의해야 합니다. Signature 속성을 통해 커맨드가 받을 입력값도 함께 정의할 수 있습니다. 커맨드가 실행되면 handle 메서드가 호출되며, 실제 로직은 이 메서드 안에 작성하면 됩니다.

예제를 하나 살펴보겠습니다. handle 메서드를 통해 필요한 의존성을 얼마든지 요청할 수 있다는 점에 주목하세요. Laravel 서비스 컨테이너가 이 메서드 시그니처에 타입힌트로 지정된 모든 의존성을 자동으로 주입해줍니다.

<?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}')] #[Description('Send a marketing email to a user')] class SendEmails extends Command { /** * 콘솔 커맨드를 실행합니다. */ public function handle(DripEmailer $drip): void { $drip->send(User::find($this->argument('user'))); } }

NOTE

코드 재사용성을 높이려면 콘솔 커맨드 자체는 가볍게 유지하고, 실제 작업은 애플리케이션 서비스에 위임하는 것이 좋습니다. 위 예제에서도 이메일 발송이라는 "실질적인 작업"은 별도의 서비스 클래스가 담당하도록 주입받고 있습니다.

종료 코드(Exit Code)

handle 메서드가 아무것도 반환하지 않고 정상적으로 실행을 마치면, 커맨드는 성공을 의미하는 0 종료 코드로 종료됩니다. 하지만 handle 메서드에서 정수를 반환하면 종료 코드를 직접 지정할 수도 있습니다.

$this->error('문제가 발생했습니다.'); return 1;

커맨드 내 어떤 메서드에서든 커맨드를 즉시 "실패" 처리하고 싶다면 fail 메서드를 사용할 수 있습니다. fail 메서드는 커맨드 실행을 즉시 종료하고 종료 코드 1을 반환합니다.

$this->fail('문제가 발생했습니다.');

클로저 기반 커맨드

콘솔 커맨드를 클래스로 정의하는 대신 클로저로 정의하는 방법도 있습니다. 라우트를 정의할 때 컨트롤러 대신 클로저를 사용할 수 있는 것처럼, 커맨드 클로저는 커맨드 클래스를 대체하는 방법이라고 생각하면 됩니다.

routes/console.php 파일은 HTTP 라우트를 정의하는 곳은 아니지만, 애플리케이션으로 진입하는 콘솔 기반의 진입점(라우트)을 정의하는 곳입니다. 이 파일 안에서 Artisan::command 메서드를 사용해 클로저 기반 콘솔 커맨드를 모두 정의할 수 있습니다. command 메서드는 두 개의 인수를 받는데, 하나는 커맨드 시그니처이고 다른 하나는 커맨드의 인수와 옵션을 전달받는 클로저입니다.

Artisan::command('mail:send {user}', function (string $user) { $this->info("Sending email to: {$user}!"); });

이 클로저는 내부적으로 커맨드 인스턴스에 바인딩되므로, 일반적인 커맨드 클래스에서 사용할 수 있는 모든 헬퍼 메서드에 그대로 접근할 수 있습니다.

의존성 타입힌트

커맨드의 인수와 옵션뿐만 아니라, 서비스 컨테이너에서 해석하고 싶은 추가 의존성도 커맨드 클로저에 타입힌트로 지정할 수 있습니다.

use App\Models\User; use App\Support\DripEmailer; use Illuminate\Support\Facades\Artisan; Artisan::command('mail:send {user}', function (DripEmailer $drip, string $user) { $drip->send(User::find($user)); });

클로저 커맨드 설명 추가하기

클로저 기반 커맨드를 정의할 때 purpose 메서드를 사용하면 커맨드에 대한 설명을 추가할 수 있습니다. 이 설명은 php artisan listphp artisan help 커맨드를 실행했을 때 표시됩니다.

Artisan::command('mail:send {user}', function (string $user) { // ... })->purpose('Send a marketing email to a user');

격리 가능한(Isolatable) 커맨드

WARNING

이 기능을 사용하려면 애플리케이션의 기본 캐시 드라이버가 memcached, redis, dynamodb, database, file, array 중 하나여야 합니다. 또한 모든 서버가 동일한 중앙 캐시 서버와 통신하고 있어야 합니다.

경우에 따라 한 번에 하나의 커맨드 인스턴스만 실행되도록 보장하고 싶을 수 있습니다. 이를 위해 커맨드 클래스에 Illuminate\Contracts\Console\Isolatable 인터페이스를 구현하면 됩니다.

<?php namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Contracts\Console\Isolatable; class SendEmails extends Command implements Isolatable { // ... }

커맨드를 Isolatable로 지정하면, 별도로 옵션을 정의하지 않아도 Laravel이 자동으로 --isolated 옵션을 사용할 수 있게 해줍니다. 이 옵션과 함께 커맨드를 실행하면, Laravel은 해당 커맨드의 다른 인스턴스가 이미 실행 중이지 않은지 확인합니다. 이는 애플리케이션의 기본 캐시 드라이버를 이용해 원자적(atomic) 락을 획득하는 방식으로 동작합니다. 만약 다른 인스턴스가 이미 실행 중이라면 해당 커맨드는 실행되지 않지만, 종료 코드는 여전히 성공을 의미하는 값으로 반환됩니다.

php artisan mail:send 1 --isolated

커맨드를 실행할 수 없었을 때 반환할 종료 코드를 직접 지정하고 싶다면, isolated 옵션에 원하는 상태 코드를 전달하면 됩니다.

php artisan mail:send 1 --isolated=12

락 ID(Lock ID)

기본적으로 Laravel은 커맨드 이름을 이용해 애플리케이션 캐시에서 원자적 락을 획득할 때 사용할 문자열 키를 생성합니다. 하지만 Artisan 커맨드 클래스에 isolatableId 메서드를 정의하면 이 키를 원하는 대로 커스터마이징할 수 있으며, 커맨드의 인수나 옵션 값을 키에 포함시킬 수도 있습니다.

/** * 커맨드의 isolatable ID를 가져옵니다. */ public function isolatableId(): string { return $this->argument('user'); }

락 만료 시간

기본적으로 격리 락(isolation lock)은 커맨드가 종료되면 함께 만료됩니다. 만약 커맨드가 중단되어 정상적으로 끝나지 못한 경우에는 1시간 후에 만료됩니다. 이 만료 시간을 조정하고 싶다면 커맨드에 isolationLockExpiresAt 메서드를 정의하면 됩니다.

use DateTimeInterface; use DateInterval; /** * 커맨드에 대한 격리 락의 만료 시점을 결정합니다. */ public function isolationLockExpiresAt(): DateTimeInterface|DateInterval { return now()->plus(minutes: 5); }

입력값 정의하기

콘솔 명령어를 작성하다 보면 인수(argument)나 옵션(option)을 통해 사용자로부터 입력을 받는 경우가 많습니다. Laravel은 명령어의 signature 속성을 통해 이러한 입력값을 매우 편리하게 정의할 수 있도록 해줍니다. signature 속성을 사용하면 명령어의 이름, 인수, 옵션을 라우트 정의와 비슷한 표현력 있는 문법으로 한 줄에 정의할 수 있습니다.

인수(Arguments)

사용자가 입력하는 모든 인수와 옵션은 중괄호({})로 감쌉니다. 아래 예시에서는 user라는 필수 인수 하나를 정의하고 있습니다.

/** * 콘솔 명령어의 이름과 시그니처 * * @var string */ protected $signature = 'mail:send {user}';

인수를 선택 사항으로 만들거나 기본값을 지정할 수도 있습니다.

// 선택적 인수... 'mail:send {user?}' // 기본값이 있는 선택적 인수... 'mail:send {user=foo}'

옵션(Options)

옵션도 인수와 마찬가지로 사용자 입력을 받는 또 다른 방법입니다. 명령줄에서 옵션을 지정할 때는 앞에 하이픈 두 개(--)를 붙입니다. 옵션에는 값을 받는 옵션과 값을 받지 않는 옵션, 두 종류가 있습니다. 값을 받지 않는 옵션은 boolean "스위치" 역할을 합니다. 예시를 살펴보겠습니다.

/** * 콘솔 명령어의 이름과 시그니처 * * @var string */ protected $signature = 'mail:send {user} {--queue}';

이 예시에서 --queue 스위치는 Artisan 명령어를 호출할 때 지정할 수 있습니다. --queue 스위치를 전달하면 해당 옵션의 값은 true가 되고, 전달하지 않으면 false가 됩니다.

php artisan mail:send 1 --queue

값을 받는 옵션

이번에는 값을 필요로 하는 옵션을 살펴보겠습니다. 사용자가 옵션에 값을 반드시 지정해야 한다면, 옵션 이름 뒤에 = 기호를 붙여줍니다.

/** * 콘솔 명령어의 이름과 시그니처 * * @var string */ protected $signature = 'mail:send {user} {--queue=}';

이렇게 정의하면 사용자는 다음과 같이 옵션 값을 전달할 수 있습니다. 명령어를 호출할 때 옵션을 지정하지 않으면 값은 null이 됩니다.

php artisan mail:send 1 --queue=default

옵션 이름 뒤에 기본값을 지정하면 옵션에 기본값을 부여할 수 있습니다. 사용자가 옵션 값을 전달하지 않으면 이 기본값이 사용됩니다.

'mail:send {user} {--queue=default}'

옵션 단축키

옵션에 단축키를 지정하려면 옵션 이름 앞에 단축키를 적고, | 문자로 단축키와 전체 옵션 이름을 구분합니다.

'mail:send {user} {--Q|queue=}'

터미널에서 명령어를 실행할 때 옵션 단축키는 하이픈 한 개만 붙이며, 값을 지정할 때는 = 문자를 사용하지 않습니다.

php artisan mail:send 1 -Qdefault

배열 형태의 입력값

인수나 옵션이 여러 개의 값을 받도록 정의하고 싶다면 * 문자를 사용하면 됩니다. 먼저 인수에 적용하는 예시를 살펴보겠습니다.

'mail:send {user*}'

이 명령어를 실행할 때 user 인수는 명령줄에 순서대로 여러 개 전달할 수 있습니다. 예를 들어 아래 명령어를 실행하면 user의 값은 12를 담은 배열이 됩니다.

php artisan mail:send 1 2

* 문자는 선택적 인수 정의와 결합해서 0개 이상의 인수를 허용하도록 할 수도 있습니다.

'mail:send {user?*}'

배열 형태의 옵션

여러 개의 입력값을 받는 옵션을 정의할 때는, 명령어에 전달하는 각 옵션 값 앞에 옵션 이름을 반복해서 붙여야 합니다.

'mail:send {--id=*}'

이런 명령어는 --id 옵션을 여러 번 전달하는 방식으로 호출할 수 있습니다.

php artisan mail:send --id=1 --id=2

입력값 설명 추가하기

인수나 옵션 이름 뒤에 콜론(:)을 붙여 설명을 추가할 수 있습니다. 명령어 정의가 길어져 조금 더 여유 있게 작성하고 싶다면, 정의를 여러 줄에 걸쳐 나눠 작성해도 무방합니다.

/** * 콘솔 명령어의 이름과 시그니처 * * @var string */ protected $signature = 'mail:send {user : The ID of the user} {--queue : Whether the job should be queued}';

누락된 입력값 자동으로 물어보기

명령어에 필수 인수가 포함되어 있는데 사용자가 이를 입력하지 않으면 에러 메시지가 표시됩니다. 이런 경우 PromptsForMissingInput 인터페이스를 구현하면, 필수 인수가 누락되었을 때 Laravel이 자동으로 사용자에게 값을 입력하도록 물어보게 만들 수 있습니다.

<?php namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Contracts\Console\PromptsForMissingInput; class SendEmails extends Command implements PromptsForMissingInput { /** * 콘솔 명령어의 이름과 시그니처 * * @var string */ protected $signature = 'mail:send {user}'; // ... }

Laravel은 사용자로부터 필수 인수를 받아야 할 때, 인수 이름이나 설명을 바탕으로 적절한 질문을 자동으로 만들어서 물어봅니다. 필수 인수를 입력받을 때 사용할 질문을 직접 지정하고 싶다면, promptForMissingArgumentsUsing 메서드를 구현하고 인수 이름을 키로 하는 질문 배열을 반환하면 됩니다.

/** * 누락된 인수 입력을 위해 반환된 질문들을 사용해 값을 입력받습니다. * * @return array<string, string> */ protected function promptForMissingArgumentsUsing(): array { return [ 'user' => 'Which user ID should receive the mail?', ]; }

질문과 플레이스홀더 텍스트를 함께 지정하려면, 질문과 플레이스홀더를 담은 튜플(배열)을 사용하면 됩니다.

return [ 'user' => ['Which user ID should receive the mail?', 'E.g. 123'], ];

프롬프트를 완전히 직접 제어하고 싶다면, 사용자에게 값을 입력받아 반환하는 클로저를 지정할 수도 있습니다.

use App\Models\User; use function Laravel\Prompts\search; // ... return [ 'user' => fn () => search( label: 'Search for a user:', placeholder: 'E.g. Taylor Otwell', options: fn ($value) => strlen($value) > 0 ? User::whereLike('name', "%{$value}%")->pluck('name', 'id')->all() : [] ), ];

NOTE

사용 가능한 프롬프트 종류와 사용법에 대한 자세한 내용은 Laravel Prompts 문서를 참고하세요.

NOTE

search 프롬프트를 사용하면 사용자가 방대한 목록에서 값을 직접 고르는 대신, 입력한 검색어에 맞춰 결과를 실시간으로 좁혀나갈 수 있습니다. 예를 들어 회원 수가 많은 서비스에서 특정 사용자를 지정해야 할 때 유용합니다.

사용자가 옵션 값을 선택하거나 입력하도록 프롬프트를 띄우고 싶다면, 명령어의 handle 메서드 안에 프롬프트 코드를 포함시키면 됩니다. 다만 누락된 인수에 대해 자동으로 프롬프트가 표시된 이후에만 추가로 프롬프트를 띄우고 싶다면, afterPromptingForMissingArguments 메서드를 구현하면 됩니다.

use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use function Laravel\Prompts\confirm; // ... /** * 사용자에게 누락된 인수를 입력받은 후 추가 작업을 수행합니다. */ protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output): void { $input->setOption('queue', confirm( label: 'Would you like to queue the mail?', default: $this->option('queue') )); }

명령어 입출력(I/O)

입력값 조회하기

명령어를 실행하는 도중에는 명령어가 받은 인수와 옵션의 값을 조회해야 하는 경우가 많습니다. 이때는 argumentoption 메서드를 사용합니다. 해당하는 인수나 옵션이 존재하지 않으면 null이 반환됩니다:

/** * 콘솔 명령어를 실행합니다. */ public function handle(): void { $userId = $this->argument('user'); }

모든 인수를 배열 형태로 한 번에 가져오고 싶다면 arguments 메서드를 호출하면 됩니다:

$arguments = $this->arguments();

옵션도 인수와 마찬가지로 option 메서드로 쉽게 조회할 수 있습니다. 모든 옵션을 배열로 가져오려면 options 메서드를 사용합니다:

// 특정 옵션 조회하기... $queueName = $this->option('queue'); // 모든 옵션을 배열로 조회하기... $options = $this->options();

input 메서드를 사용하면 명령어의 인수와 옵션을 Illuminate\Console\CommandInput 인스턴스로 조회할 수 있습니다. 이 인스턴스는 HTTP 요청 등 다른 데이터 컨테이너에서 제공하는 것과 동일한 타입 기반 접근자(accessor)를 제공합니다:

use App\Enums\ReportType; /** * 콘솔 명령어를 실행합니다. */ public function handle(): void { $input = $this->input()->date('from'); // ... }

input 메서드는 인수와 옵션 중 하나의 값을 이름으로 직접 조회할 때도 사용할 수 있습니다:

$queue = $this->input('queue', 'default');

입력 요청하기

NOTE

Laravel Prompts는 브라우저와 유사한 플레이스홀더 텍스트, 유효성 검증 등의 기능을 갖춘, 세련되고 사용하기 편리한 CLI 폼을 손쉽게 만들 수 있는 PHP 패키지입니다.

명령어는 단순히 결과를 출력하는 것뿐만 아니라, 실행 도중 사용자에게 값을 입력받을 수도 있습니다. ask 메서드는 지정한 질문을 사용자에게 보여주고 입력을 받은 뒤, 그 값을 반환합니다:

/** * 콘솔 명령어를 실행합니다. */ public function handle(): void { $name = $this->ask('이름이 무엇인가요?'); // ... }

ask 메서드는 두 번째 인수로 기본값을 받을 수 있으며, 사용자가 아무 값도 입력하지 않았을 때 이 기본값이 반환됩니다:

$name = $this->ask('이름이 무엇인가요?', 'Taylor');

secret 메서드는 ask와 비슷하지만, 사용자가 입력하는 내용이 콘솔 화면에 표시되지 않습니다. 비밀번호처럼 민감한 정보를 입력받을 때 유용합니다:

$password = $this->secret('비밀번호를 입력하세요');

확인(Yes/No) 요청하기

사용자에게 단순히 "예/아니오" 형태의 확인을 받아야 한다면 confirm 메서드를 사용할 수 있습니다. 이 메서드는 기본적으로 false를 반환하지만, 사용자가 y 또는 yes를 입력하면 true를 반환합니다.

if ($this->confirm('계속 진행하시겠습니까?')) { // ... }

필요하다면 confirm 메서드의 두 번째 인수로 true를 전달해서, 사용자가 아무 입력도 하지 않았을 때 기본값이 true가 되도록 지정할 수도 있습니다:

if ($this->confirm('계속 진행하시겠습니까?', true)) { // ... }

자동 완성

anticipate 메서드를 사용하면 선택 가능한 값들에 대해 자동 완성 기능을 제공할 수 있습니다. 자동 완성 힌트가 제공되더라도 사용자는 원하는 값을 자유롭게 입력할 수 있습니다:

$name = $this->anticipate('이름이 무엇인가요?', ['Taylor', 'Dayle']);

또는 anticipate 메서드의 두 번째 인수로 클로저를 전달할 수도 있습니다. 이 클로저는 사용자가 문자를 입력할 때마다 호출되며, 지금까지 입력된 문자열을 매개변수로 받아 자동 완성 후보 목록을 배열로 반환해야 합니다:

use App\Models\Address; $name = $this->anticipate('주소가 무엇인가요?', function (string $input) { return Address::whereLike('name', "{$input}%") ->limit(5) ->pluck('name') ->all(); });

객관식 질문

사용자에게 정해진 선택지 중에서 값을 고르도록 하고 싶다면 choice 메서드를 사용할 수 있습니다. 세 번째 인수로 배열 인덱스를 전달하면, 아무것도 선택하지 않았을 때 반환될 기본값을 지정할 수 있습니다:

$name = $this->choice( '이름이 무엇인가요?', ['Taylor', 'Dayle'], $defaultIndex );

또한 choice 메서드는 네 번째, 다섯 번째 인수로 각각 유효한 응답을 선택하기까지의 최대 시도 횟수와 다중 선택 허용 여부를 지정할 수 있습니다:

$name = $this->choice( '이름이 무엇인가요?', ['Taylor', 'Dayle'], $defaultIndex, $maxAttempts = null, $allowMultipleSelections = false );

출력하기

콘솔에 결과를 출력할 때는 line, newLine, info, comment, question, warn, alert, error 메서드를 사용할 수 있습니다. 각 메서드는 용도에 맞는 ANSI 색상을 사용해 출력합니다. 예를 들어, 사용자에게 일반적인 안내 정보를 보여준다고 해봅시다. 보통 info 메서드는 콘솔에서 초록색 텍스트로 표시됩니다:

/** * 콘솔 명령어를 실행합니다. */ public function handle(): void { // ... $this->info('명령어가 성공적으로 실행되었습니다!'); }

오류 메시지를 표시하려면 error 메서드를 사용하세요. 오류 메시지는 보통 빨간색으로 표시됩니다:

$this->error('문제가 발생했습니다!');

특별한 색상 없이 일반 텍스트를 출력하려면 line 메서드를 사용합니다:

$this->line('화면에 이 내용을 표시합니다');

빈 줄을 출력하려면 newLine 메서드를 사용합니다:

// 빈 줄 하나 출력하기... $this->newLine(); // 빈 줄 세 개 출력하기... $this->newLine(3);

테이블

여러 행과 열로 구성된 데이터를 올바른 형식으로 보여줘야 할 때는 table 메서드가 매우 유용합니다. 열 이름과 테이블에 표시할 데이터만 전달하면, Laravel이 알맞은 테이블의 너비와 높이를 자동으로 계산해 출력해줍니다:

use App\Models\User; $this->table( ['Name', 'Email'], User::all(['name', 'email'])->toArray() );

진행률 표시줄(Progress Bar)

오래 걸리는 작업을 처리할 때는 진행 상황을 알려주는 진행률 표시줄을 보여주는 것이 도움이 됩니다. withProgressBar 메서드를 사용하면, 주어진 반복 가능한(iterable) 값을 순회하는 동안 Laravel이 자동으로 진행률 표시줄을 표시하고 갱신해줍니다:

use App\Models\User; $users = $this->withProgressBar(User::all(), function (User $user) { $this->performTask($user); });

경우에 따라 진행률 표시줄이 진행되는 방식을 좀 더 세밀하게 직접 제어해야 할 수도 있습니다. 이럴 때는 먼저 전체 처리 단계 수를 정의한 다음, 각 항목을 처리할 때마다 진행률 표시줄을 한 단계씩 진행시키면 됩니다:

$users = App\Models\User::all(); $bar = $this->output->createProgressBar(count($users)); $bar->start(); foreach ($users as $user) { $this->performTask($user); $bar->advance(); } $bar->finish();

NOTE

더 다양한 옵션이 궁금하다면 Symfony Progress Bar 컴포넌트 문서를 참고하세요.

커맨드 등록하기

기본적으로 Laravel은 app/Console/Commands 디렉터리 안에 있는 모든 커맨드를 자동으로 등록합니다. 하지만 필요하다면 애플리케이션의 bootstrap/app.php 파일에서 withCommands 메서드를 사용해 Laravel이 다른 디렉터리도 스캔하도록 지정할 수 있습니다.

->withCommands([ __DIR__.'/../app/Domain/Orders/Commands', ])

예를 들어 도메인 주도 설계(DDD) 방식으로 프로젝트를 구성해서 커맨드 클래스들이 app/Console/Commands가 아닌 다른 위치에 흩어져 있는 경우, 위와 같이 원하는 경로를 추가로 등록해 주면 됩니다.

필요하다면 커맨드 클래스 이름을 withCommands 메서드에 직접 전달해서 수동으로 등록할 수도 있습니다.

use App\Domain\Orders\Commands\SendEmails; ->withCommands([ SendEmails::class, ])

Artisan이 부팅될 때, 애플리케이션에 등록된 모든 커맨드는 서비스 컨테이너를 통해 해석(resolve)된 뒤 Artisan에 등록됩니다.

코드에서 Artisan 명령어 실행하기

CLI가 아닌 곳에서 Artisan 명령어를 실행해야 할 때가 있습니다. 예를 들어 라우트나 컨트롤러 안에서 Artisan 명령어를 실행하고 싶은 경우가 그렇습니다. 이럴 때는 Artisan 파사드의 call 메서드를 사용하면 됩니다. call 메서드는 첫 번째 인자로 명령어의 시그니처 이름 또는 클래스명을, 두 번째 인자로 명령어 파라미터 배열을 받으며, 실행 후 종료 코드(exit code)를 반환합니다.

use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Route; Route::post('/user/{user}/mail', function (string $user) { $exitCode = Artisan::call('mail:send', [ 'user' => $user, '--queue' => 'default' ]); // ... });

또는 전체 Artisan 명령어를 하나의 문자열로 call 메서드에 전달할 수도 있습니다.

Artisan::call('mail:send 1 --queue=default');

배열 값 전달하기

명령어에 배열 값을 받는 옵션이 정의되어 있다면, 해당 옵션에 배열을 전달하면 됩니다.

use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Route; Route::post('/mail', function () { $exitCode = Artisan::call('mail:send', [ '--id' => [5, 13] ]); });

불리언 값 전달하기

migrate:refresh 명령어의 --force 플래그처럼 문자열 값을 받지 않는 옵션의 값을 지정해야 한다면, 해당 옵션의 값으로 true 또는 false를 전달하면 됩니다.

$exitCode = Artisan::call('migrate:refresh', [ '--force' => true, ]);

Artisan 명령어 큐에 등록하기

Artisan 파사드의 queue 메서드를 사용하면 Artisan 명령어를 큐에 등록하여, 큐 워커가 백그라운드에서 처리하도록 만들 수도 있습니다. 이 메서드를 사용하기 전에 큐 설정을 마치고 큐 리스너가 실행 중인지 확인하세요.

use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Route; Route::post('/user/{user}/mail', function (string $user) { Artisan::queue('mail:send', [ 'user' => $user, '--queue' => 'default' ]); // ... });

onConnection, onQueue 메서드를 사용하면 Artisan 명령어를 어느 커넥션과 큐로 디스패치할지 지정할 수 있습니다.

Artisan::queue('mail:send', [ 'user' => 1, '--queue' => 'default' ])->onConnection('redis')->onQueue('commands');

다른 명령어에서 명령어 호출하기

기존 Artisan 명령어 안에서 또 다른 명령어를 호출하고 싶을 때도 있습니다. 이럴 때는 call 메서드를 사용하면 됩니다. 이 call 메서드는 명령어 이름과 인자 / 옵션 배열을 인자로 받습니다.

/** * 콘솔 명령어를 실행합니다. */ public function handle(): void { $this->call('mail:send', [ 'user' => 1, '--queue' => 'default' ]); // ... }

다른 콘솔 명령어를 호출하면서 해당 명령어의 출력을 모두 감추고 싶다면 callSilently 메서드를 사용할 수 있습니다. callSilently 메서드는 call 메서드와 동일한 시그니처를 가집니다.

$this->callSilently('mail:send', [ 'user' => 1, '--queue' => 'default' ]);

#시그널 처리

운영체제는 실행 중인 프로세스에 시그널(signal)을 보낼 수 있습니다. 예를 들어 SIGTERM 시그널은 운영체제가 프로그램에게 "정상적으로 종료해 달라"고 요청하는 방식입니다. Artisan 콘솔 명령어에서 이러한 시그널을 감지하고 원하는 코드를 실행하고 싶다면 trap 메서드를 사용하면 됩니다:

/** * 콘솔 명령어를 실행합니다. */ public function handle(): void { $this->trap(SIGTERM, fn () => $this->shouldKeepRunning = false); while ($this->shouldKeepRunning) { // ... } }

여러 시그널을 한 번에 감지하고 싶다면 trap 메서드에 시그널 배열을 전달하면 됩니다:

$this->trap([SIGTERM, SIGQUIT], function (int $signal) { $this->shouldKeepRunning = false; dump($signal); // SIGTERM / SIGQUIT });

NOTE

예를 들어 큐 워커나 장시간 실행되는 배치 작업처럼 무한 루프를 도는 명령어를 작성할 때, trap 메서드를 활용하면 SIGTERM 시그널을 받았을 때 현재 작업을 안전하게 마무리하고 루프를 빠져나가도록 구현할 수 있습니다. 이렇게 하면 배포 시 서버가 프로세스를 강제 종료하기 전에, 진행 중이던 작업이 깨지지 않고 깔끔하게 종료될 기회를 얻게 됩니다.

Dev 명령어

dev Artisan 명령어는 로컬 개발에 필요한 여러 프로세스를 하나의 터미널 창에서 동시에 실행해주는 편리한 명령어입니다. 기본적으로 PHP 개발 서버, 큐 워커, Pail을 이용한 로그 확인, Vite 에셋 컴파일까지 한 번에 실행됩니다:

php artisan dev

내부적으로 dev 명령어는 @laravel/multiplex라는 npm 패키지를 사용해 프로세스를 관리합니다. 각 프로세스는 별도의 탭에서 실행되며, 검색과 스크롤이 가능한 출력을 제공합니다. 프로세스마다 이름과 색상이 지정되어 있어 어떤 출력이 어떤 프로세스에서 나온 것인지 쉽게 구분할 수 있습니다. 프로세스가 비정상 종료되면 자동으로 재시작되며, 명령어를 종료할 때는 지금까지의 모든 출력 내용이 터미널에 그대로 남기 때문에 로그가 유실될 걱정이 없습니다.

NOTE

dev 명령어를 사용하려면 Node 22.13 이상이 필요합니다. Windows 환경에서는 concurrently npm 패키지를 대신 사용하며, 탭 인터페이스는 지원되지 않습니다.

기본으로 실행되는 프로세스는 다음과 같습니다.

이름명령어
serverphp artisan serve --host=localhost
queuephp artisan queue:listen --tries=1 --timeout=0
logsphp artisan pail --timeout=0
vitenpm run dev

NOTE

vite 프로세스는 프로젝트에서 사용 중인 Node 패키지 매니저(npm, pnpm, Yarn, Bun 중 하나)를 자동으로 감지해 그에 맞는 실행 명령어를 사용합니다.

Dev 프로세스 커스터마이징

dev 명령어가 실행하는 프로세스는 DevCommands 클래스를 이용해 원하는 대로 바꿀 수 있습니다. 보통 애플리케이션의 AppServiceProviderboot 메서드 안에서 설정합니다. register 메서드는 실행할 명령어 문자열과 (선택적으로) 프로세스 이름을 인자로 받습니다:

use Illuminate\Foundation\DevCommands; /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { DevCommands::register('some-command --flag', 'my-process'); }

Artisan 명령어를 등록할 때는 artisan 메서드를 사용하면 자동으로 명령어 앞에 php artisan이 붙습니다:

DevCommands::artisan('horizon', 'horizon');

마찬가지로 node 메서드는 감지된 패키지 매니저의 run 명령어(예: npm run)를 앞에 붙여주고, nodeExec 메서드는 패키지 매니저의 exec 명령어(예: npx)를 앞에 붙여줍니다:

DevCommands::node('storybook', 'storybook'); DevCommands::nodeExec('tailwindcss -i resources/css/app.css -o public/css/app.css --watch', 'tailwind');

기본 프로세스와 동일한 이름으로 프로세스를 등록하면 기존 기본 프로세스를 대체합니다. 예를 들어 서버 프로세스가 사용하는 포트를 바꾸고 싶다면 다음과 같이 작성하면 됩니다:

DevCommands::artisan('serve --host=localhost --port=9000', 'server');

터미널에 표시되는 프로세스 라벨의 색상도 지정할 수 있습니다. 사용 가능한 색상 메서드는 blue, purple, pink, orange, green, yellow이며, color 메서드에 원하는 hex 색상 값을 직접 전달할 수도 있습니다:

DevCommands::register('my-command', 'my-process')->green(); DevCommands::register('my-command', 'my-process')->color('#ff6347');

프로세스를 실제로 실행하지 않고 현재 등록된 dev 프로세스 목록만 확인하고 싶다면 dev:list 명령어를 사용하세요:

php artisan dev:list

실패한 프로세스 재시작

프로세스가 비정상 종료되면 Laravel은 잠깐의 지연 후 자동으로 재시작을 시도합니다. 최대 5회까지 재시도한 뒤에도 계속 실패하면 그 프로세스는 "실패" 상태로 표시됩니다. 단, 프로세스가 시작 후 1초 이내에 종료된 경우에는 애초에 정상적으로 시작되지 못했을 가능성이 높기 때문에 재시작을 시도하지 않습니다. r 키를 눌러 프로세스를 수동으로 재시작하면 재시도 횟수 카운터가 초기화됩니다.

한 번 실행할 때만 이 자동 재시작 동작을 끄고 싶다면 --no-restart 옵션을 사용하면 됩니다:

php artisan dev --no-restart

또는 애플리케이션 전체에서 이 기능을 아예 비활성화하려면 disableAutoRestart 메서드를 사용하세요:

DevCommands::disableAutoRestart();

Dev 프로세스 필터링

only 메서드를 사용하면 dev 명령어 실행 시 지정한 프로세스만 실행되도록 제한할 수 있습니다. 반대로 except 메서드를 사용하면 특정 프로세스를 실행 대상에서 제외할 수 있습니다:

// server와 vite 프로세스만 실행합니다... DevCommands::only('server', 'vite'); // 큐 워커를 제외한 모든 프로세스를 실행합니다... DevCommands::except('queue');

패키지에서 등록한 명령어나 Laravel의 기본 명령어를 제외하고 싶다면 withoutVendorCommandswithoutDefaultCommands 메서드를 사용하면 됩니다:

DevCommands::withoutVendorCommands(); DevCommands::withoutDefaultCommands();

스텁 커스터마이징

Artisan 콘솔의 make 계열 명령어들은 컨트롤러, Job, 마이그레이션, 테스트 등 다양한 클래스를 생성할 때 사용됩니다. 이 클래스들은 "스텁(stub)" 파일을 기반으로 생성되는데, 스텁 파일 안의 자리 표시자가 여러분이 입력한 값으로 채워지는 방식입니다. 그런데 경우에 따라 Artisan이 생성하는 파일의 내용을 조금씩 수정하고 싶을 수 있습니다. 이럴 때는 stub:publish 명령어를 사용해 자주 쓰이는 스텁 파일들을 애플리케이션에 퍼블리시(게시)한 뒤 자유롭게 수정할 수 있습니다:

php artisan stub:publish

퍼블리시된 스텁 파일은 애플리케이션 루트의 stubs 디렉터리에 위치하게 됩니다. 이 파일들을 수정하면, 이후 Artisan의 make 명령어로 해당 클래스를 생성할 때마다 수정한 내용이 그대로 반영됩니다.

NOTE

예를 들어 팀 내부 컨벤션에 맞춰 컨트롤러 생성 시 항상 특정 트레이트를 사용하도록 하거나, 모델 생성 시 기본적으로 특정 네임스페이스를 사용하도록 스텁을 수정해두면, 매번 생성 후 수동으로 고칠 필요 없이 일관된 코드 스타일을 유지할 수 있습니다.

이벤트

Artisan은 명령어를 실행하는 동안 세 가지 이벤트를 발생시킵니다: Illuminate\Console\Events\ArtisanStarting, Illuminate\Console\Events\CommandStarting, Illuminate\Console\Events\CommandFinished가 그것입니다.

  • ArtisanStarting 이벤트는 Artisan이 실행을 시작하는 즉시 발생합니다.
  • CommandStarting 이벤트는 특정 명령어가 실행되기 직전에 발생합니다.
  • CommandFinished 이벤트는 명령어 실행이 끝난 직후에 발생합니다.

이 이벤트들을 활용하면 명령어 실행 전후로 로깅을 남기거나, 특정 명령어 실행을 감지해 알림을 보내는 등의 부가 작업을 손쉽게 구현할 수 있습니다.

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 9월 15일