Unsubscribe from a channel
Send phx_leave for a Realtime channel and wait for the server's ack.
Tear down a single channel's subscription. unsubscribe flips the channel state to LEAVING, emits a phx_leave push to the server, and stays in LEAVING until the server acks (or errors / times out). Once the ack arrives, the channel goes to CLOSED, every registered on_close hook fires, and the channel is removed from client.channels so it stops receiving dispatched frames.
To also close the underlying socket when the registry empties, use remove_channel instead — unsubscribe only tears down this one channel.
Signature
channel.unsubscribeParameters
This method has no parameters.
Returns
Returns the channel. The leave is in flight when this method returns; the channel is still in LEAVING until the server replies. Idempotent — calling unsubscribe on an already-CLOSED channel is a no-op.
Example — unsubscribe a single channel
channel = supabase.channel("public:countries").on_postgres_changes("*", schema: "public", table: "countries") { |p| handle(p) }.subscribe
# ...some work...
channel.unsubscribeExample — wait for CLOSED before exiting
unsubscribe returns before the server acks. Hook on_close to know when the leave is fully done — useful in test teardown or short-lived scripts.
done = Queue.new
channel.on_close { done.push(:closed) }
channel.unsubscribe
done.pop # blocks until phx_leave is acked (or times out → on_close still fires via on_leave_ack)Example — re-subscribing requires a fresh channel
subscribe may only be called once per channel object. To re-subscribe to the same topic after an unsubscribe, open a new channel.
channel.unsubscribe
# A new channel for the same topic.
channel = supabase
.channel("public:countries")
.on_postgres_changes("*", schema: "public", table: "countries") { |p| handle(p) }
.subscribeLifecycle
- Pre-condition: channel is
JOINED(orJOINING). OnCLOSED/LEAVING,unsubscribeis a no-op. - State flips to
LEAVING. Thephx_leavepush is registered inpending_pusheswith a 10s timeout. - Server replies with
phx_reply→on_leave_ack→ state toCLOSED,on_closehooks fire, rejoin timer reset. - Server replies with
phx_reply(error) or no reply within 10s → stillon_leave_ack(same handler for all three statuses), so the channel cleans up locally regardless of server response. - After CLOSED, the channel is removed from
client.channelsviaClient#_remove_channel. It's no longer dispatched to.
Synchronous return; server ack arrives later
unsubscribe is synchronous — it returns once the phx_leave frame is queued (or sent, if connected). The actual server ack arrives asynchronously on the read-thread, which is why on_close is the only reliable way to detect "leave fully complete". For non-blocking teardown of multiple channels, use supabase.remove_channel(channel) from the top-level client under async: true — it returns an Async::Task you can .wait on (see remove_channel).