---
term: 'GraphQL Subscriptions vs. WebSocket nei backend gestiti'
seoTitle: 'GraphQL Subscriptions vs. WebSocket: protocollo vs. trasporto'
headline: 'GraphQL Subscriptions vs. WebSocket: che cosa si confronta davvero?'
slug: graphql-subscriptions-vs-websockets
category: api-realtime
shortDefinition: 'Una subscription GraphQL è un flusso di eventi tipizzato e definito dallo schema; un WebSocket è il trasporto grezzo su cui di solito viaggia.'
relatedTerms:
  - graphql
  - websockets-real-time-sync
  - real-time-live-queries
  - sse-vs-websockets-vs-polling
contrastsWith:
  - websockets-real-time-sync
aboutTerms:
  - 'GraphQL Subscriptions'
  - 'WebSockets'
faq:
  - question: 'Le subscription GraphQL sono la stessa cosa dei WebSocket?'
    answer: 'No – vivono in livelli diversi. Un WebSocket è un trasporto: un canale di byte persistente e full-duplex, senza alcuna opinione su ciò che lo attraversa. Una subscription GraphQL è un protocollo e un contratto posati sopra: un''operazione definita nello schema i cui eventi arrivano tipizzati, validati e con la stessa forma di qualsiasi altra risposta GraphQL. Confrontarli direttamente è come confrontare una strada con una linea di autobus.'
  - question: 'Quale protocollo usano le subscription GraphQL?'
    answer: 'Nella maggior parte dei casi graphql-ws, il sotto-protocollo moderno di GraphQL su WebSocket: il client apre un socket, invia connection_init, riceve connection_ack, poi avvia le operazioni con messaggi subscribe; il server trasmette payload next per id di subscription e uno dei due lati chiude con complete. Un sotto-protocollo più vecchio, ereditato dai primi tempi dell''ecosistema, circola ancora – per questo client e server devono accordarsi su quale dei due parlano.'
  - question: 'Le subscription GraphQL possono viaggiare su Server-Sent Events?'
    answer: 'Sì – il contratto di subscription è indipendente dal trasporto, e SSE è un vettore legittimo e sempre più diffuso. Poiché il traffico delle subscription va quasi esclusivamente dal server al client, un flusso HTTP unidirezionale si adatta in modo naturale, va d''accordo con i proxy ordinari e con la semantica HTTP, e porta con sé la riconnessione automatica senza costi. I WebSocket restano la scelta predefinita della maggior parte degli strumenti, ma "le subscription richiedono i WebSocket" è folklore, non un fatto.'
  - question: 'Quando usare WebSocket grezzi invece delle subscription GraphQL?'
    answer: 'Quando il traffico smette di assomigliare a eventi API tipizzati: frame binari (audio, stato di gioco, flussi di sensori), frequenze di messaggi molto alte in cui la validazione dello schema e la busta JSON per evento costano throughput reale, oppure protocolli che richiedono una semantica propria – cursori, delta, ack – in conflitto con la forma della subscription. Se non c''è già un investimento in uno schema GraphQL, un socket grezzo evita anche di importarne uno solo per gli eventi.'
  - question: 'Le subscription GraphQL scalano?'
    answer: 'Il trasporto scala come qualsiasi flotta di WebSocket – stato delle connessioni, routing con affinità (sticky) e backplane pub/sub fra server. Il livello di subscription aggiunge un asse proprio: ogni evento può essere risolto e filtrato per sottoscrittore, quindi un topic caldo con molti sottoscrittori moltiplica il lavoro dei resolver. Le piattaforme gestite assorbono la flotta; la progettazione dello schema e la disciplina nei filtri per sottoscrittore restano in mano a chi sviluppa.'
  - question: 'Le subscription GraphQL sono la stessa cosa delle live query?'
    answer: 'Parenti strette, con trigger diversi. Le subscription scattano su eventi nominati cablati esplicitamente – una mutation pubblica su un topic, i sottoscrittori ricevono. Le live query scattano sui cambiamenti dell''insieme di risultati di una query – nessun cablaggio di eventi, ogni percorso di scrittura coperto automaticamente. Entrambe viaggiano di solito su WebSocket. Un livello di live query scambia la progettazione degli eventi schema-first con il rilevamento automatico dei cambiamenti sui dati stessi.'
  - question: 'Perché le subscription hanno bisogno di un sotto-protocollo?'
    answer: 'Perché un WebSocket nudo è solo una sequenza ordinata di byte. Nel momento in cui due parti devono multiplexare più subscription su un solo socket, correlare gli eventi alle operazioni, negoziare l''autenticazione, segnalare gli errori e chiudere i flussi in modo pulito, servono un framing dei messaggi e delle regole – che ogni team un tempo ha inventato male, ciascuno in una versione incompatibile. graphql-ws standardizza esattamente quel livello perché client e server possano interoperare.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'Subscriptions — graphql.org'
    url: 'https://graphql.org/learn/subscriptions/'
  - name: 'GraphQL over WebSocket Protocol (graphql-ws)'
    url: 'https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md'
  - name: 'RFC 6455 — The WebSocket Protocol'
    url: 'https://datatracker.ietf.org/doc/html/rfc6455'
  - name: 'The WebSocket API — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API'
  - name: 'GraphQL — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/GraphQL'
  - name: 'WebSocket — Wikipedia'
    url: 'https://en.wikipedia.org/wiki/WebSocket'
cta:
  title: 'Tempo reale senza possedere nessuno dei due livelli'
  text: 'Back4app affianca un''API GraphQL generata automaticamente alle Live Queries – subscription tipizzate, con permessi verificati, su una flotta di WebSocket gestita. Definisci lo schema, sottoscrivi la query e salta del tutto l''ingegneria del protocollo.'
  linkText: 'Inizia gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-10-23'
translationKey: graphql-subscriptions-vs-websockets
---

**Una subscription GraphQL è un flusso di eventi tipizzato e definito dallo schema; un WebSocket è il trasporto grezzo su cui di solito viaggia.** Il "vs." del titolo nasconde una confusione di livelli che conviene sciogliere prima di qualsiasi decisione: le subscription non sono un'*alternativa* ai WebSocket – sono una delle cose che si possono far girare *sopra* un WebSocket, come HTTP gira sopra TCP. La scelta vera è fra un protocollo tipizzato che qualcun altro ha specificato e un canale grezzo il cui protocollo resta da inventare.

## Punti chiave

| Domanda | Risposta |
| --- | --- |
| WebSocket | Un canale di byte persistente e full-duplex – nessuna semantica dei messaggi inclusa |
| Subscription GraphQL | Un flusso di eventi definito dallo schema, tipizzato e validato come qualsiasi risposta GraphQL |
| La loro relazione | Livelli sovrapposti, non rivali – le subscription viaggiano su WebSocket (o SSE) tramite un sotto-protocollo |
| Il sotto-protocollo | graphql-ws: handshake init/ack, id che multiplexano le operazioni, frame next/complete |
| La decisione vera | Protocollo tipizzato pronto all'uso vs. socket grezzo + un protocollo di cui farsi carico |

## I livelli, in codice

Che cos'è davvero una subscription nel traffico di rete – una conversazione [graphql-ws](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) dentro un WebSocket:

```json
// client → server, una volta aperto il socket
{ "type": "connection_init", "payload": { "authToken": "…" } }
// server → client
{ "type": "connection_ack" }
// il client avvia un'operazione – l'id multiplexa questa subscription
{ "type": "subscribe", "id": "1", "payload": {
    "query": "subscription { orderUpdated(status: PREPARING) { id status eta } }" } }
// il server trasmette eventi tipizzati, un frame per occorrenza
{ "type": "next", "id": "1", "payload": { "data": { "orderUpdated": { "id": "o42", "status": "READY", "eta": null } } } }
// uno dei due lati chiude il flusso
{ "type": "complete", "id": "1" }
```

E quello che scrive davvero la maggior parte del codice applicativo – una subscription tipizzata con l'intero stack gestito:

**JavaScript:**

```javascript
// JavaScript — Back4app JS SDK
// A typed subscription over a managed WebSocket fleet: the protocol,
// reconnects, and fan-out are the platform's problem, not yours
const orders = new Parse.Query('Order');
orders.equalTo('status', 'preparing');

const sub = await orders.subscribe();
sub.on('create', (o) => addCard(o));      // typed event, full object
sub.on('update', (o) => refreshCard(o));
sub.on('leave',  (o) => removeCard(o));   // edited out of the result set

sub.on('close', () => showOfflineBadge()); // socket lifecycle surfaced
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// A typed subscription over a managed WebSocket fleet: the protocol,
// reconnects, and fan-out are the platform's problem, not yours
final liveQuery = LiveQuery();
final orders = QueryBuilder<ParseObject>(ParseObject('Order'))
  ..whereEqualTo('status', 'preparing');

final sub = await liveQuery.client.subscribe(orders);
sub.on(LiveQueryEvent.create, (o) => addCard(o));    // typed event
sub.on(LiveQueryEvent.update, (o) => refreshCard(o));
sub.on(LiveQueryEvent.leave, (o) => removeCard(o));  // left the set
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// A typed subscription over a managed WebSocket fleet: the protocol,
// reconnects, and fan-out are the platform's problem, not yours
let orders = Order.query("status" == "preparing")

let subscription = orders.subscribeCallback
subscription?.handleEvent { _, event in
  switch event {
  case .created(let o): addCard(o)       // typed event, full object
  case .updated(let o): refreshCard(o)
  case .left(let o):    removeCard(o)    // edited out of the result set
  default:              break
  }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// A typed subscription over a managed WebSocket fleet: the protocol,
// reconnects, and fan-out are the platform's problem, not yours
val client = ParseLiveQueryClient.Factory.getClient()
val orders = ParseQuery.getQuery<ParseObject>("Order")
orders.whereEqualTo("status", "preparing")

val sub = client.subscribe(orders)
sub.handleEvent(SubscriptionHandling.Event.CREATE) { _, o -> addCard(o) }
sub.handleEvent(SubscriptionHandling.Event.UPDATE) { _, o -> refreshCard(o) }
sub.handleEvent(SubscriptionHandling.Event.LEAVE)  { _, o -> removeCard(o) }
```

## Uno stack, tre livelli

```mermaid
flowchart TB
  accTitle: Subscription GraphQL sovrapposte a un trasporto WebSocket
  accDescr: Il codice applicativo consuma eventi tipizzati. Sotto, un protocollo di subscription come graphql-ws gestisce handshake, multiplexing e ciclo di vita dei flussi. Più in basso, il livello di trasporto è di solito un WebSocket e a volte Server-Sent Events. Il trasporto muove byte; il protocollo dà loro un significato; lo schema dà loro i tipi.
  A["Codice applicativo<br/>eventi tipizzati, payload nella forma dello schema"] --> P["Protocollo di subscription – graphql-ws<br/>connection_init/ack · subscribe · next · complete"]
  P --> T["Trasporto – di solito WebSocket, a volte SSE<br/>connessione persistente, consegna ordinata"]
  T --> N["TCP/IP"]
```

Il livello [WebSocket](/glossary/it/websockets/) ([RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455)) promette esattamente questo: un flusso persistente, full-duplex e ordinato di frame di testo o binari, raggiungibile da qualsiasi browser tramite [una piccola API](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). Non dice nulla su che cosa un messaggio *significhi* – nessuna correlazione richiesta/risposta, nessuna convenzione di autenticazione, nessuna segnalazione degli errori, nessun modo di far passare due flussi logici su un solo socket. Ogni progetto su socket grezzo ridecide tutto da capo.

Il [livello di subscription](https://graphql.org/learn/subscriptions/) è precisamente quell'insieme di decisioni mancanti, standardizzato: `connection_init`/`connection_ack` trasporta l'autenticazione; gli `id` per operazione multiplexano molte subscription su un solo socket; i frame `next` consegnano payload che sono normali risposte GraphQL – tipizzate dallo schema, validate, ispezionabili, consumate dalla stessa macchina client di query e mutation; `complete` chiude un flusso senza uccidere i vicini. Una nota storica conta nella pratica: un sotto-protocollo più vecchio, ereditato dai primi tempi dell'ecosistema, è ancora in produzione, e un client che parla l'uno con un server che parla l'altro fallisce in modi silenziosi e sconcertanti – conviene fissare esplicitamente il sotto-protocollo a entrambe le estremità.

E poiché il contratto riguarda i messaggi, non i socket, il trasporto sottostante è intercambiabile – la stessa semantica di subscription gira sempre più spesso su Server-Sent Events, che si adatta alla forma quasi esclusivamente unidirezionale del traffico delle subscription ed eredita [la compatibilità di SSE con i proxy e la riconnessione automatica](/glossary/it/sse-vs-websockets-vs-polling/). "Subscription vs. WebSocket" si dissolve al primo contatto: uno è un contratto, l'altro un vettore.

## Subscription GraphQL vs. WebSocket grezzi

| | Subscription GraphQL | WebSocket grezzi |
| --- | --- | --- |
| Livello | Protocollo + sistema di tipi sopra un trasporto | Il trasporto stesso |
| Contratto dei messaggi | Definito dallo schema, validato, ispezionabile | Quello che si inventa e si documenta |
| Multiplexing | Integrato – id per operazione su un solo socket | Da progettare in proprio |
| Handshake di autenticazione | Standardizzato (payload di `connection_init`) | Da progettare in proprio |
| Payload | JSON, nella forma dello schema | Testo **e binario**, qualsiasi formato |
| Filtri | Argomenti sul campo della subscription | Codice server da scrivere |
| Overhead per evento | Busta JSON + esecuzione dei resolver | ~2–14 byte di framing |
| Ecosistema | Client GraphQL, codegen, strumenti | Librerie di socket nudi |
| Ideale quando | Gli eventi sono dati API tipizzati in un'app GraphQL | Binario, alta frequenza o semantica personalizzata |

## Quando i socket grezzi battono le subscription tipizzate

I casi onesti esistono, solo più stretti di quanto suggerisca l'entusiasmo per il socket grezzo. **Payload binari** – frammenti audio, protocol buffer, stato di gioco – viaggiano nativamente nei frame WebSocket ma andrebbero codificati dentro una busta JSON di subscription. **Frequenza dei messaggi** – a migliaia di eventi al secondo per client, l'esecuzione dei resolver e la busta JSON per evento smettono di essere rumore; un formato di frame compatto e personalizzato è un'ottimizzazione legittima. **Semantica personalizzata** – backpressure, ack lato client, codifica a delta, cursori ripristinabili – appartiene ai protocolli progettati in proprio, e innestarla sui frame di subscription significa lottare contro la specifica. E **nessun GraphQL in partenza** – adottare schema, resolver e strumenti client *solo* per avere eventi tipizzati significa lasciare che un dettaglio detti l'intera architettura; un socket grezzo con un formato dei messaggi documentato è più piccolo. La trappola funziona anche al contrario: i team che scelgono socket grezzi per eventi API tipizzati in forma JSON finiscono per scrivere a mano multiplexing, handshake di autenticazione e semantica di riconnessione – un graphql-ws peggiore, un team incompatibile alla volta.

## Casi d'uso tipici

- **Flussi di ordini e stati** – "una notifica quando questo ordine cambia": dati API tipizzati, frequenza bassa, il terreno ideale delle subscription.
- **Presenza e commenti collaborativi** – subscription in app GraphQL che già possiedono lo schema; gli eventi sono solo altro schema.
- **Ticker finanziari e dashboard** – subscription finché i payload restano in forma JSON; socket grezzi quando la cadenza dei tick esige frame compatti.
- **Chat** – entrambi i livelli funzionano; il voto decisivo è di solito se l'app è GraphQL-first, dato che le [live query](/glossary/it/live-queries-tempo-reale/) coprono lo stesso terreno senza cablaggio di eventi.
- **Stato multigiocatore e media** – binario, alta frequenza, critico per la latenza: territorio del WebSocket grezzo, protocollo compreso.

## Subscription GraphQL o WebSocket grezzi? Matrice decisionale

| Situazione | Scegliere |
| --- | --- |
| L'app parla già [GraphQL](/glossary/it/graphql/); gli eventi sono dati API tipizzati | Subscription GraphQL |
| Frame binari, o migliaia di eventi/s per client | WebSocket grezzi |
| Servono semantiche personalizzate – ack, delta, cursori, backpressure | WebSocket grezzi, con protocollo documentato |
| Nessun investimento in GraphQL, semplice feed di eventi | Socket grezzo con un piccolo protocollo a frame – oppure SSE |
| Gli eventi significano "i risultati di questa query sono cambiati" | Un livello di live query – nessun cablaggio di eventi |
| Proxy rigidi, infrastruttura solo HTTP | Subscription su SSE |
| Team piccolo, nessuna voglia di possedere un protocollo | Subscription tipizzate su un backend gestito |

## Limiti e trade-off

- **Le subscription ereditano l'esercizio dei WebSocket.** Sovrapporre livelli aggiunge significato, non magia: stato delle connessioni, routing con affinità, heartbeat e backplane pub/sub fra server restano la realtà del deployment sottostante.
- **La riconnessione perde comunque eventi.** graphql-ws definisce flussi, non ripresa: un socket caduto significa frame persi, e il recupero (rieseguire la query, poi risottoscrivere) è logica applicativa su entrambi gli stack.
- **La risoluzione per sottoscrittore costa.** Le subscription filtrate possono eseguire resolver e verifiche dei permessi per evento e per sottoscrittore – un topic caldo con migliaia di ascoltatori le moltiplica; conviene progettare filtri lato server, e stretti.
- **Circolano due sotto-protocolli.** I protocolli GraphQL-over-WebSocket legacy e moderno sono reciprocamente incomprensibili; estremità disallineate falliscono in silenzio. Le versioni vanno fissate esplicitamente.
- **Le buste tipizzate tassano il throughput.** Serializzazione JSON e validazione dello schema per evento sono invisibili a decine di eventi al secondo e dominanti a migliaia – misurare prima di dare per scontato l'uno o l'altro esito.

## GraphQL Subscriptions e WebSocket su Back4app

Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. I livelli descritti in questo articolo si ritrovano tali e quali sulla piattaforma: l'API GraphQL generata automaticamente copre i livelli query e mutation a partire dallo schema senza una riga di resolver, mentre il livello in tempo reale arriva sotto forma di [Live Queries](/glossary/it/live-queries-tempo-reale/) – eventi di sottoscrizione tipizzati e verificati dalle ACL su una flotta di WebSocket gestita, che usano il protocollo aperto LiveQuery al posto di graphql-ws e scattano sui cambiamenti dell'insieme di risultati invece che su eventi cablati a mano. Si ottiene la colonna "protocollo tipizzato" della tabella comparativa – multiplexing, autenticazione e gestione della riconnessione compresi – senza gestire la flotta di socket né possedere la specifica di un protocollo.
