SwoffSwoff

Server Push

Real-time cache invalidation from the Service Worker via SSE or WebSocket.

If you're coming from Socket.io for real-time updates: Swoff's server push connects to your SSE or WebSocket endpoint from the Service Worker, not from the page. The connection survives navigation, tab refresh, and doesn't consume page memory. When the server sends tags, the SW invalidates cached responses across all tabs — no need to manually wire up socket events to cache invalidation. See the GraphQL & Push architecture.

Preconditions

  • Swoff initialized with data fetching enabled and tagInvalidation configured
  • Cookie auth required — bearer and custom auth are incompatible (the SW has no DOM to refresh tokens)
  • A server endpoint that sends SSE events or WebSocket messages

Status

Disabled by default. Server push must be explicitly enabled.

Enable

npx @swoff/cli add server-push

Or set config manually:

{
  "features": {
    "serverPush": {
      "enabled": true,
      "type": "sse",
      "endpoint": "/api/events",
      "reconnectDelayMs": 5000
    }
  }
}

Generated files

FileWhat it doesImport in your code?
swoff/server-push/client.tsSSE/WS connection manager (runs in SW, no page imports needed)No — auto-managed by SW
swoff-api.bundle.jsstartPushEvents(), stopPushEvents(), isPushConnected() on window.swoff for no-bundler projectsNo (auto-initializes)

No page-side imports needed for bundler projects — the SW connects to your endpoint on activation and manages reconnection. For no-bundler projects, the swoff-api.bundle.js exposes swoff.startPushEvents() / swoff.stopPushEvents() / swoff.isPushConnected() to control the server-push connection from the page.

Usage

Server sends tags for invalidation

// SSE event data or WebSocket message:
{
  "tags": ["notes", "users:456"]
}

The SW receives this and calls invalidateByTags(["notes", "users:456"]). All tabs re-fetch the affected data on their next fetchWithCache call.

Multiple tags per event

{
  "tags": ["notes", "dashboard", "stats:*"]
}

Supports glob patterns — stats:* invalidates all cache entries under any stats:* tag.

Connection lifecycle

The SW manages:

  • Auto-connect on SW activation
  • Reconnect with exponential backoff (respects reconnectDelayMs)
  • Connection survives navigation and tab refresh
  • Connection drops when the SW is terminated (browser idle) — re-established on next navigation or push

Customize

Connection parameters are config-only. No generated files to edit.

To customize reconnection behavior, adjust reconnectDelayMs in config. The SW doubles the delay on each failure, capped by the initial value.

Config

{
  "features": {
    "tagInvalidation": {},
    "serverPush": {
      "enabled": true,
      "type": "sse",
      "endpoint": "/api/events",
      "reconnectDelayMs": 5000
    }
  }
}
  • type"sse" (Server-Sent Events) or "websocket"
  • endpoint — URL of your server push endpoint
  • reconnectDelayMs — initial reconnect delay; doubles on each failure (capped at this value)

Framework adapters

Server push invalidates cache entries in the SW, which dispatches cache-invalidated to all clients — the same event consumed by useSwoffFetch. The flow:

Server sends tags via SSE/WS
  → SW calls invalidateByTags(tags)
    → SW invalidates matching cache entries
      → SW broadcasts cache-invalidated to all tabs
        → Your adapter re-fetches affected data

Event:

EventDetail shapePurpose
cache-invalidated{ tags }SW invalidated entries — refetch data whose URL tags intersect

The adapter pattern is identical to the one described in the Tag Invalidation guide — the only difference is the source of invalidation (server push instead of manual calls). See the Blueprint for the event reference and adapter patterns.

Important: tagInvalidation is required

Server push works by calling invalidateByTags() in the SW. The tagInvalidation configuration object must be present in your config for tags to be generated and invalidated. Server push requires tag invalidation to be active.

SSE vs WebSocket

AspectSSEWebSocket
DirectionServer → client onlyBidirectional
ReconnectionBuilt-in (EventSource API)Manual (Swoff handles it)
PayloadText onlyText or binary
Browser supportAll modern browsersAll modern browsers
When to useSimple push from serverNeed 2-way communication

On this page