© 2026 Hedgehog Software, LLC

TwitterGitHubDiscord
More
CommunitiesDocsAboutTermsPrivacy
Search
Star
Setup for Free
SupabaseS
Supabase•2mo ago•
1 reply
okee

Supabase Realtime in long-running Node.js — is manual channel re-subscription required?

realtime🟡javascript
Hi everyone 👋

I have a Node.js server running 24/7 using Supabase Realtime to listen to an
activities
activities
table and send push notifications.

It works initially, but after some time, the server stops receiving events — even though the process runs, network is stable, and no errors are logged.

Environment: Node.js,
@supabase/supabase-js
@supabase/supabase-js
(latest),
postgres_changes
postgres_changes
, service role key

Current implementation:
const supabase = createSupabaseClient<Database>(config.url, config.secretKey);

supabase.realtime
  .channel(`sync-activities-${uuidv4()}`)
  .on("postgres_changes", { event: "*", schema: "public", table: "activities" },
    async (payload) => { /* send push */ }
  )
  .subscribe();
const supabase = createSupabaseClient<Database>(config.url, config.secretKey);

supabase.realtime
  .channel(`sync-activities-${uuidv4()}`)
  .on("postgres_changes", { event: "*", schema: "public", table: "activities" },
    async (payload) => { /* send push */ }
  )
  .subscribe();


My understanding:
supabase-js
supabase-js
handles WebSocket reconnects but doesn't guarantee channel/subscription recovery — channels can silently become inactive.

Proposed fix:
const subscribe = () => {
  const channel = supabase.realtime
    .channel(`sync-activities-${uuidv4()}`)
    .on("postgres_changes", { event: "*", schema: "public", table: "activities" },
      async (payload) => { /* process */ }
    )
    .subscribe(async (status, err) => {
      if (status === "SUBSCRIBED") return;
      if (["CLOSED", "CHANNEL_ERROR", "TIMED_OUT"].includes(status)) {
        await supabase.removeChannel(channel);
        subscribe();
      }
    });
};
subscribe();
const subscribe = () => {
  const channel = supabase.realtime
    .channel(`sync-activities-${uuidv4()}`)
    .on("postgres_changes", { event: "*", schema: "public", table: "activities" },
      async (payload) => { /* process */ }
    )
    .subscribe(async (status, err) => {
      if (status === "SUBSCRIBED") return;
      if (["CLOSED", "CHANNEL_ERROR", "TIMED_OUT"].includes(status)) {
        await supabase.removeChannel(channel);
        subscribe();
      }
    });
};
subscribe();


Questions:
1. Is this the recommended pattern for long-running workers?
2. Is manual channel recreation expected in production?
3. Any best practices (heartbeat, watchdog, backoff) for this use case?

Thanks — happy to share findings once resolved 🙏
Supabase banner
SupabaseJoin
Supabase gives you the tools, documentation, and community that makes managing databases, authentication, and backend infrastructure a lot less overwhelming.
45,816Members
Resources
Was this page helpful?

Similar Threads

Recent Announcements

Similar Threads

realtime-js channel subscription status is TIMED_OUT
SupabaseSSupabase / help-and-questions
3y ago
realtime subscription reliability
SupabaseSSupabase / help-and-questions
7mo ago
Realtime not working in supabase-js 2.54+
SupabaseSSupabase / help-and-questions
5mo ago
supabase realtime in python
SupabaseSSupabase / help-and-questions
3y ago