function

quic.listen

function listen(
onsession: OnSessionCallback,
options?: SessionOptions
): Promise<QuicEndpoint>;

Configures the endpoint to listen as a server. When a new session is initiated by a remote peer, the given onsession callback will be invoked with the created session.

import { listen } from 'node:quic';

const endpoint = await listen((session) => {
  // ... handle the session
});

// Closing the endpoint allows any sessions open when close is called
// to complete naturally while preventing new sessions from being
// initiated. Once all existing sessions have finished, the endpoint
// will be destroyed. The call returns a promise that is resolved once
// the endpoint is destroyed.
await endpoint.close();

By default, every call to listen(...) will create a new local QuicEndpoint instance bound to a new random local IP port. To specify the exact local address to use, or to multiplex multiple QUIC sessions over a single local port, pass the endpoint option with either a QuicEndpoint or EndpointOptions as the argument.

At most, any single QuicEndpoint can only be configured to listen as a server once.

Referenced types

type OnSessionCallback = (this: QuicEndpoint, session: QuicSession) => void

interface SessionOptions

  • alpn?: string | readonly string[]

    The ALPN (Application-Layer Protocol Negotiation) identifier(s).

    For client sessions, this is a single string specifying the protocol the client wants to use (e.g. 'h3').

    For server sessions, this is an array of protocol names in preference order that the server supports (e.g. ['h3', 'h3-29']). During the TLS handshake, the server selects the first protocol from its list that the client also supports.

    The negotiated ALPN determines which Application implementation is used for the session. 'h3' and 'h3-*' variants select the HTTP/3 application; all other values select the default application.

  • application?: ApplicationOptions

    Application-specific options.

  • ca?: ArrayBuffer | ArrayBufferView<ArrayBufferLike> | readonly unknown[]

    The CA certificates to use for client sessions. For server sessions, CA certificates are specified per-identity in the sessionOptions.sni map.

  • cc?: 'reno' | 'cubic' | 'bbr'

    Specifies the congestion control algorithm that will be used. Must be set to one of either 'reno', 'cubic', or 'bbr'.

    This is an advanced option that users typically won't have need to specify.

  • certs?: ArrayBuffer | ArrayBufferView<ArrayBufferLike> | readonly unknown[]

    The TLS certificates to use for client sessions. For server sessions, certificates are specified per-identity in the sessionOptions.sni map.

  • ciphers?: string

    The list of supported TLS 1.3 cipher algorithms.

  • crl?: ArrayBuffer | ArrayBufferView<ArrayBufferLike> | readonly unknown[]

    The CRL to use for client sessions. For server sessions, CRLs are specified per-identity in the sessionOptions.sni map.

  • datagramDropPolicy?: 'drop-oldest' | 'drop-newest'

    Controls which datagram to drop when the pending datagram queue (sized by session.maxPendingDatagrams) is full. Must be one of 'drop-oldest' (discard the oldest queued datagram to make room) or 'drop-newest' (reject the incoming datagram). Dropped datagrams are reported as lost via the ondatagramstatus callback.

    This option is immutable after session creation.

  • drainingPeriodMultiplier?: number

    A multiplier applied to the Probe Timeout (PTO) to compute the draining period duration after receiving a CONNECTION_CLOSE frame from the peer. RFC 9000 Section 10.2 requires the draining period to persist for at least three times the current PTO. The valid range is 3 to 255. Values below 3 are clamped to 3.

  • enableEarlyData?: boolean

    When true, enables TLS 0-RTT early data for this session. Early data allows the client to send application data before the TLS handshake completes, reducing latency on reconnection when a valid session ticket is available. Set to false to disable early data support.

  • endpoint?: QuicEndpoint | EndpointOptions

    An endpoint to use.

  • groups?: string

    The list of supported TLS 1.3 cipher groups.

  • handshakeTimeout?: number | bigint

    Specifies the keep-alive timeout in milliseconds. When set to a non-zero value, PING frames will be sent automatically to keep the connection alive before the idle timeout fires. The value should be less than the effective idle timeout (maxIdleTimeout transport parameter) to be useful.

  • keylog?: boolean

    When true, enables TLS key logging for the session. Key material is delivered to the session.onkeylog callback in NSS Key Log Format. Each callback invocation receives a single line of key material. The output can be used with tools such as Wireshark to decrypt captured QUIC traffic.

  • keys?: KeyObject | readonly KeyObject[]

    The TLS crypto keys to use for client sessions. For server sessions, keys are specified per-identity in the sessionOptions.sni map.

  • maxDatagramSendAttempts?: number

    The maximum number of SendPendingData cycles a datagram can survive without being sent before it is abandoned. When a datagram cannot be sent due to congestion control or packet size constraints, it remains in the queue and the attempt counter increments. Once the limit is reached, the datagram is dropped and reported as 'abandoned' via the ondatagramstatus callback. Valid range: 1 to 255.

  • maxPayloadSize?: number | bigint

    Specifies the maximum UDP packet payload size.

  • maxStreamWindow?: number | bigint

    Specifies the maximum stream flow-control window size.

  • maxWindow?: number | bigint

    Specifies the maximum session flow-control window size.

  • minVersion?: number

    The minimum QUIC version number to allow. This is an advanced option that users typically won't have need to specify.

  • onearlyrejected?: (this: QuicSession) => void
  • onerror?: (this: QuicSession, error: any) => void
  • ongoaway?: (this: QuicSession, lastStreamId: bigint) => void
  • onheaders?: (this: QuicStream, headers: Dict<string | string[]>) => void
  • oninfo?: (this: QuicStream, headers: Dict<string | string[]>) => void
  • ontrailers?: (this: QuicStream, trailers: Dict<string | string[]>) => void
  • onwanttrailers?: (this: QuicStream) => void
  • preferredAddressPolicy?: 'ignore' | 'default' | 'use'

    When the remote peer advertises a preferred address, this option specifies whether to use it or ignore it. The default is 'ignore' because honoring a server's preferred address causes the client to migrate its connection to a different IP address, which can be exploited for data exfiltration attacks that are indistinguishable from legitimate QUIC connection migration at the network level. Set to 'use' only when connecting to trusted servers that require preferred address migration.

  • qlog?: boolean

    When true, enables qlog diagnostic output for the session. Qlog data is delivered to the session.onqlog callback as chunks of JSON-SEQ formatted text. The output can be analyzed with qlog visualization tools such as qvis.

  • rejectUnauthorized?: boolean

    If true, the peer certificate is verified against the list of supplied CAs. An error is emitted if verification fails; the error can be inspected via the validationErrorReason and validationErrorCode fields in the handshake callback. If false, peer certificate verification errors are ignored.

  • reuseEndpoint?: boolean

    When true (the default), connect() will attempt to reuse an existing endpoint rather than creating a new one for each session. This provides connection pooling behavior — multiple sessions can share a single UDP socket. The reuse logic will not return an endpoint that is listening on the same address as the connect target (to prevent CID routing conflicts).

    Set to false to force creation of a new endpoint for the session. This is useful when endpoint isolation is required (e.g., testing stateless reset behavior where source port identity matters).

  • servername?: string

    The peer server name to target (SNI). Defaults to 'localhost'.

  • sessionTicket?: ArrayBufferView<ArrayBufferLike>

    A session ticket to use for 0RTT session resumption.

  • sni?: Record<string, SNIEntry>

    An object mapping host names to TLS identity options for Server Name Indication (SNI) support. This is required for server sessions and must contain at least one entry. The special key '*' specifies the optional default/fallback identity used when no other host name matches. If no wildcard entry is provided, connections with unrecognized server names will be rejected with a TLS unrecognized_name alert. Each entry may contain:

  • streamIdleTimeout?: number | bigint

    The maximum time in milliseconds that a peer-initiated stream can be idle (no data received) before it is automatically destroyed. This protects against slowloris-style attacks where a remote peer opens streams but never sends data, holding server resources indefinitely. Only peer-initiated streams are checked — locally-initiated streams are the application's responsibility. Set to 0 to disable.

    The idle check runs as part of the normal send processing loop, so it adds no additional timers or event loop overhead. The session.stats.streamsIdleTimedOut counter tracks how many streams have been destroyed by this mechanism.

  • tlsTrace?: boolean

    True to enable TLS tracing output.

  • token?: ArrayBufferView<ArrayBufferLike>

    An opaque address validation token previously received from the server via the session.onnewtoken callback. Providing a valid token on reconnection allows the client to skip the server's address validation, reducing handshake latency.

  • transportParams?: TransportParams

    The QUIC transport parameters to use for the session.

  • unacknowledgedPacketThreshold?: number | bigint

    Specifies the maximum number of unacknowledged packets a session should allow.

  • verifyClient?: boolean

    True to require verification of TLS client certificate.

  • verifyPeer?: 'strict' | 'auto' | 'manual'

    Controls how the client handles server certificate validation:

    • 'strict' — OpenSSL aborts the TLS handshake immediately if the server's certificate fails validation. The session.opened promise rejects with a TLS error. The application cannot inspect the certificate or the error details. This is the most secure mode.

    • 'auto' — The TLS handshake completes regardless of validation result. If validation fails, the session.opened promise is rejected with an error containing the validation reason, and the session is destroyed. The onhandshake callback (if set) fires before rejection, allowing diagnostic logging. This is the default and matches the behavior of tls.connect() with rejectUnauthorized: true.

    • 'manual' — The TLS handshake completes regardless of validation result. The session.opened promise resolves with the handshake info, which includes validationErrorReason and validationErrorCode if validation failed. The application is responsible for checking these values and deciding whether to continue. Use this mode for custom validation logic, certificate pinning, or intentionally accepting self-signed certificates.

  • verifyPrivateKey?: boolean

    True to require private key verification for client sessions. For server sessions, this option is specified per-identity in the sessionOptions.sni map.

  • version?: number

    The QUIC version number to use. This is an advanced option that users typically won't have need to specify.

namespace QuicEndpoint

  • class Stats

    A view of the collected statistics for an endpoint.

    • readonly bytesReceived: bigint

      The total number of bytes received by this endpoint. Read only.

    • readonly bytesSent: bigint

      The total number of bytes sent by this endpoint. Read only.

    • readonly clientSessions: bigint

      The total number of sessions initiated by this endpoint. Read only.

    • readonly createdAt: bigint

      A timestamp indicating the moment the endpoint was created. Read only.

    • readonly destroyedAt: bigint

      A timestamp indicating the moment the endpoint was destroyed. Read only.

    • readonly immediateCloseCount: bigint

      The total number of immediate connection close packets sent by this endpoint. Read only.

    • readonly immediateCloseRateLimited: bigint

      The total number of immediate connection close packets dropped by the global rate limiter. Read only.

    • readonly packetsBlocked: bigint

      The total number of incoming packets dropped by the block list filter. Read only.

    • readonly packetsReceived: bigint

      The total number of QUIC packets successfully received by this endpoint. Read only.

    • readonly packetsSent: bigint

      The total number of QUIC packets successfully sent by this endpoint. Read only.

    • readonly retryCount: bigint

      The total number of retry packets sent by this endpoint. Read only.

    • readonly retryRateLimited: bigint

      The total number of retry packets dropped by the global rate limiter. Read only. A non-zero value indicates the endpoint is under retry flood pressure.

    • readonly serverBusyCount: bigint

      The total number of times an initial packet was rejected due to the endpoint being marked busy. Read only.

    • readonly serverSessions: bigint

      The total number of peer-initiated sessions received by this endpoint. Read only.

    • readonly sessionCreationRateLimited: bigint

      The total number of session creation attempts dropped by the per-host rate limiter. Read only. A non-zero value indicates one or more remote addresses are creating sessions faster than the configured rate allows.

    • readonly statelessResetCount: bigint

      The total number of stateless reset packets sent by this endpoint. Read only.

    • readonly statelessResetRateLimited: bigint

      The total number of stateless reset packets dropped by the global rate limiter. Read only.

    • readonly versionNegotiationCount: bigint

      The total number of version negotiation packets sent by this endpoint. Read only.

    • readonly versionNegotiationRateLimited: bigint

      The total number of version negotiation packets dropped by the global rate limiter. Read only.