Skip to main content
moq-lite is the core transport layer for Media over QUIC, providing a generic pub/sub protocol built on WebTransport and QUIC.
This crate implements a simplified subset of the IETF MoQ specification, focusing on practical features and deployability. It’s highly recommended to use moq-lite instead of the full IETF standard until at least draft-30.

Overview

moq-lite is designed for real-time live media delivery with sub-second latency at massive scale. It provides:
  • Broadcasts: Discoverable collections of tracks
  • Tracks: Named streams of data, split into groups
  • Groups: Sequential collections of frames, delivered out-of-order until expired
  • Frames: Chunks of data with an upfront size

Installation

Add to your Cargo.toml:
[dependencies]
moq-lite = "0.15"

Features

  • serde: Enable serialization support for data structures

Core API

The API is built around Producer/Consumer pairs with a clear hierarchy:

Origin

A collection of broadcasts, produced by one or more sessions.
use moq_lite::Origin;

// Create a producer/consumer pair
let origin = Origin::produce();
let origin_producer = origin.clone();
let origin_consumer = origin.consume();

// Publish a broadcast to the origin
origin_producer.publish_broadcast("my-broadcast", broadcast.consume());
See Origin on docs.rs

Broadcast

A collection of tracks, produced by a single publisher.
use moq_lite::Broadcast;

// Create a broadcast
let mut broadcast = Broadcast::produce();

// Create tracks within the broadcast
let track = broadcast.create_track(Track {
    name: "video".to_string(),
    priority: 0,
})?;
See Broadcast on docs.rs

Track

A collection of groups, delivered out-of-order until expired.
use moq_lite::Track;

// Create a track
let mut track = broadcast.create_track(Track {
    name: "audio".to_string(),
    priority: 1,  // Higher priority = delivered first
})?;

// Append a group to the track
let mut group = track.append_group()?;

// Or write a single-frame group
track.write_frame(bytes::Bytes::from("data"))?;
See Track on docs.rs

Group

A collection of frames, delivered in order until cancelled.
// Create a group
let mut group = track.append_group()?;

// Write multiple frames
group.write_frame(bytes::Bytes::from("frame1"))?;
group.write_frame(bytes::Bytes::from("frame2"))?;

// Finish the group
group.finish()?;
See Group on docs.rs

Frame

Chunks of data with an upfront size.
use bytes::Bytes;

// Write a frame
group.write_frame(Bytes::from("data"))?;
See Frame on docs.rs

Client and Server

moq-lite provides low-level client and server implementations. For most use cases, use moq-native which provides higher-level helpers.

Client

Connect to a relay as a client:
use moq_lite::Client;

// Typically used via moq-native::ClientConfig
let client = moq_native::ClientConfig::default().init()?;
let session = client.connect(url).await?;
See Client on docs.rs

Server

Accept connections as a server:
use moq_lite::Server;

// Typically used via moq-native::ServerConfig
let server = moq_native::ServerConfig::default().init()?;
let session = server.accept().await?;
See Server on docs.rs

Session

Represents an active MoQ connection:
// Wait until the session is closed
session.closed().await?;
See Session on docs.rs

Complete Example

use moq_lite::{Origin, Broadcast, Track};
use bytes::Bytes;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Create an origin
    let origin = Origin::produce();
    
    // Create a broadcast
    let mut broadcast = Broadcast::produce();
    
    // Create a track
    let mut track = broadcast.create_track(Track {
        name: "data".to_string(),
        priority: 0,
    })?;
    
    // Publish the broadcast
    origin.publish_broadcast("my-app", broadcast.consume());
    
    // Write data to the track
    track.write_frame(Bytes::from_static(b"Hello, MoQ!"))?;
    
    Ok(())
}

Architecture

moq-lite operates at the transport layer, below media-specific logic:
Application     ← Your business logic

  hang          ← Media codecs (optional)

moq-lite        ← Generic pub/sub (this crate)

WebTransport    ← QUIC + HTTP/3

Error Handling

All operations return Result<T, moq_lite::Error>:
match track.write_frame(data) {
    Ok(()) => println!("Frame written"),
    Err(e) => eprintln!("Error: {}", e),
}
See Error on docs.rs

Resources

Next Steps

moq-native

Helper library for native applications

hang

Media-specific layer built on moq-lite

Getting Started

Build your first application

moq-relay

Deploy a relay server

Build docs developers (and LLMs) love