메인 콘텐츠로 건너뛰기

브로드캐스팅이란

WebSocket을 사용하면 서버에서 클라이언트로 실시간으로 데이터를 전송할 수 있습니다. Laravel의 브로드캐스팅은 서버 사이드의 이벤트를 WebSocket 경유로 프런트엔드의 JavaScript에 전달하는 구조입니다. 예를 들어 주문 상태가 변화했을 때, 페이지를 재로드하지 않아도 브라우저 상에서 즉시 업데이트를 표시할 수 있습니다. 서버 사이드의 이벤트 이름과 데이터를 클라이언트 사이드와 그대로 공유할 수 있는 것이 Laravel 브로드캐스팅의 강점입니다.
브로드캐스팅은 Laravel의 이벤트 시스템 위에 구축되어 있습니다. 먼저 이벤트와 리스너의 기본을 이해해 두는 것을 권장합니다.

셋업

신규 Laravel 애플리케이션에서 브로드캐스팅은 기본적으로 무효입니다. install:broadcasting Artisan 명령어로 유효화합니다.
php artisan install:broadcasting
이 명령어를 실행하면 사용할 브로드캐스팅 서비스를 선택하도록 촉구됩니다. 또한 config/broadcasting.phproutes/channels.php가 생성됩니다.

Laravel Reverb

Laravel 11 이후에서는 공식 WebSocket 서버인 Laravel Reverb가 권장됩니다. Reverb는 셀프 호스트형으로, 추가의 외부 서비스 없이 실시간 통신을 실현합니다.

설치

install:broadcasting 명령어에 --reverb 옵션을 붙이면, Reverb에 필요한 Composer 패키지·NPM 패키지의 설치와 .env의 설정을 일괄로 수행합니다.
php artisan install:broadcasting --reverb
수동으로 설치하는 경우, Composer로 패키지를 추가한 후에 설치 명령어를 실행합니다.
composer require laravel/reverb

php artisan reverb:install

.env 의 주요 설정값

BROADCAST_CONNECTION=reverb

REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=http

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

Reverb 서버 기동

php artisan reverb:start
운영 환경에서는 Supervisor 등의 프로세스 매니저로 데몬으로서 관리합니다.
브로드캐스팅 이벤트는 큐 경유로 처리됩니다. Reverb 서버와는 별도로 큐 워커도 기동해 두어야 합니다.
php artisan queue:work

브로드캐스팅 이벤트 작성

이벤트 클래스 생성

php artisan make:event OrderShipmentStatusUpdated
생성된 이벤트 클래스에 ShouldBroadcast 인터페이스를 구현합니다.
<?php

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class OrderShipmentStatusUpdated implements ShouldBroadcast
{
    use InteractsWithSockets, SerializesModels;

    public function __construct(
        public Order $order,
    ) {}

    /**
     * 이벤트를 브로드캐스트할 채널을 반환
     */
    public function broadcastOn(): Channel
    {
        return new PrivateChannel('orders.' . $this->order->id);
    }
}
ShouldBroadcast를 구현하는 것만으로 이벤트가 발화되면 자동으로 큐 경유로 브로드캐스트됩니다.

브로드캐스팅 데이터 커스터마이즈

기본적으로 이벤트 클래스의 public 프로퍼티가 모두 브로드캐스팅의 페이로드에 포함됩니다. 전송할 데이터를 좁히려면 broadcastWith 메서드를 정의합니다.
public function broadcastWith(): array
{
    return [
        'order_id' => $this->order->id,
        'status'   => $this->order->status,
    ];
}

브로드캐스팅 이름 커스터마이즈

기본적으로 클래스 이름이 이벤트 이름이 됩니다. broadcastAs 메서드로 커스텀 이름을 지정할 수 있습니다.
public function broadcastAs(): string
{
    return 'order.status.updated';
}
프런트엔드에서 리스닝할 때는 선두에 .을 붙여 앱의 네임스페이스 프리픽스를 무효화합니다.
Echo.private(`orders.${orderId}`)
    .listen('.order.status.updated', (e) => {
        console.log(e);
    });

채널의 종류

채널클래스설명
PublicChannel인증 불필요. 누구나 구독 가능
PrivatePrivateChannel인증된 사용자만. 인가 로직이 필요
PresencePresenceChannelPrivate의 확장. 채널의 참가자 목록을 취득 가능
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;

// Public 채널
public function broadcastOn(): Channel
{
    return new Channel('posts');
}

// Private 채널
public function broadcastOn(): Channel
{
    return new PrivateChannel('orders.' . $this->order->id);
}

// Presence 채널
public function broadcastOn(): Channel
{
    return new PresenceChannel('rooms.' . $this->room->id);
}
여러 채널로 브로드캐스트하려면 배열로 반환합니다.
public function broadcastOn(): array
{
    return [
        new PrivateChannel('orders.' . $this->order->id),
        new Channel('admin.orders'),
    ];
}

채널 인가

Private 채널과 Presence 채널은 구독 전에 서버 사이드에서 인가 체크가 수행됩니다.

routes/channels.php

install:broadcasting 명령어로 생성되는 routes/channels.php에 인가 콜백을 정의합니다.
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
    return $user->id === Order::findOrNew($orderId)->user_id;
});
콜백의 첫 번째 인수는 인증된 사용자, 이후의 인수는 채널 이름의 와일드카드입니다. true 또는 truthy한 값을 반환하면 인가 성공, false를 반환하면 거부됩니다.
라우트 모델 바인딩도 사용할 수 있습니다. 채널 이름을 orders.{order}로 하면 Order 모델의 인스턴스가 전달됩니다.
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->user_id;
});

채널 클래스에 의한 인가

채널이 늘어난 경우, 채널 클래스를 사용해 정리할 수 있습니다.
php artisan make:channel OrderChannel
<?php

namespace App\Broadcasting;

use App\Models\Order;
use App\Models\User;

class OrderChannel
{
    public function join(User $user, Order $order): bool
    {
        return $user->id === $order->user_id;
    }
}
routes/channels.php에서 등록합니다.
use App\Broadcasting\OrderChannel;

Broadcast::channel('orders.{order}', OrderChannel::class);

이벤트 발화

ShouldBroadcast를 구현한 이벤트는 일반적인 이벤트와 동일하게 발화합니다.
use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);
자기 자신을 제외한 다른 사용자에게만 브로드캐스트하고 싶은 경우 toOthers를 사용합니다.
broadcast(new OrderShipmentStatusUpdated($order))->toOthers();
toOthers를 사용하려면 이벤트 클래스가 InteractsWithSockets 트레이트를 사용하고 있어야 합니다.

프런트엔드에서의 수신

Laravel Echo 셋업

Reverb를 사용하는 경우, resources/js/bootstrap.js에 Echo 인스턴스를 설정합니다.
npm install --save-dev laravel-echo pusher-js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

이벤트 리스닝

// Public 채널
Echo.channel('posts')
    .listen('PostPublished', (e) => {
        console.log(e.post);
    });

// Private 채널
Echo.private(`orders.${orderId}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order);
    });

// Presence 채널
Echo.join(`rooms.${roomId}`)
    .here((users) => {
        console.log('현재 멤버:', users);
    })
    .joining((user) => {
        console.log(user.name, '가 참가했습니다');
    })
    .leaving((user) => {
        console.log(user.name, '가 퇴장했습니다');
    })
    .listen('MessagePosted', (e) => {
        console.log(e.message);
    });

React / Vue 훅의 사용

React·Vue의 스타터 킷을 사용하고 있는 경우, 전용 훅을 사용하면 간결하게 쓸 수 있습니다.
import { useEcho } from "@laravel/echo-react";

// Private 채널
useEcho(
    `orders.${orderId}`,
    "OrderShipmentStatusUpdated",
    (e) => {
        console.log(e.order);
    },
);

// Public 채널
import { useEchoPublic } from "@laravel/echo-react";

useEchoPublic("posts", "PostPublished", (e) => {
    console.log(e.post);
});
useEcho 훅은 컴포넌트의 언마운트 시에 자동으로 채널을 이탈합니다.
프런트엔드의 애셋을 빌드하기 전에, .envVITE_REVERB_* 변수가 올바르게 설정되어 있는지 확인해 주십시오.
npm run build

실전 예시: 주문 상태의 실시간 업데이트

1

브로드캐스팅을 유효화

php artisan install:broadcasting --reverb
Reverb 서버와 큐 워커를 기동합니다.
php artisan reverb:start
php artisan queue:work
2

이벤트 클래스를 작성

php artisan make:event OrderShipmentStatusUpdated
app/Events/OrderShipmentStatusUpdated.php를 편집합니다.
<?php

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class OrderShipmentStatusUpdated implements ShouldBroadcast
{
    use InteractsWithSockets, SerializesModels;

    public function __construct(
        public Order $order,
    ) {}

    public function broadcastOn(): Channel
    {
        return new PrivateChannel('orders.' . $this->order->id);
    }

    public function broadcastWith(): array
    {
        return [
            'order_id' => $this->order->id,
            'status'   => $this->order->status,
        ];
    }
}
3

채널 인가를 정의

routes/channels.php에 인가 로직을 추가합니다.
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->user_id;
});
4

이벤트를 발화

주문 상태를 업데이트하는 컨트롤러나 Job에서 발화합니다.
use App\Events\OrderShipmentStatusUpdated;

$order->update(['status' => 'shipped']);

OrderShipmentStatusUpdated::dispatch($order);
5

프런트엔드에서 리스닝

Blade 템플릿에 인라인 스크립트, 또는 React/Vue 컴포넌트로 수신합니다.
Echo.private(`orders.${orderId}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        document.getElementById('status').textContent = e.status;
    });

다음 단계

Laravel Reverb

Reverb 서버의 셋업, 운영 환경에서의 운용, 스케일링의 세부 사항을 확인하십시오.

큐와 잡

브로드캐스팅은 큐 경유로 처리됩니다. 큐의 설정과 운용 방법을 확인하십시오.

이벤트와 리스너

브로드캐스팅의 기반이 되는 Laravel 이벤트 시스템의 세부 사항을 배웁니다.
마지막 수정일 2026년 7월 13일