Next.js, NestJS, 100ms, GraphQL, RabbitMQ
Vonza — Live Streaming Feature
The complete live streaming module for Vonza — a large multi-tenant SaaS platform for creators and educators — enabling hosts to broadcast live inside communities, courses, and personal rooms.
Resources
A short demo showing the full workflow — host creates the room, guest joins via invite link, stream ends, recording saves automatically.
What needed to be solved
Vonza already had a scheduling feature that let admins book slots for in-person meetings or video calls using external links (Google Meet, Zoom). The client wanted to replace that dependency with a fully owned system. Separately, inside communities and courses, creators needed the ability to go live and broadcast directly to their audience within the platform — similar to going live on Facebook. Both needs required building a real-time streaming system from the ground up.
Key Decisions & Challenges
Choosing 100ms Over Agora, Twilio, and Custom Infrastructure
Situation
We needed a real-time video and streaming service that could ship fast, support multiple room types and recording, and integrate cleanly with our Next.js and NestJS stack. Five options were formally evaluated.
Options Considered
- Agora.io — lower cost at scale, battle-tested infrastructure, but no prebuilt UI components and a longer development runway
- Twilio Video — enterprise-grade but significantly more expensive and complex relative to what we needed
- AWS Chime SDK — technically capable but required deep AWS expertise we didn't have on the team, and an estimated 12–16 weeks to ship
- Custom WebRTC infrastructure (Janus, Kurento, or Mediasoup) — full control but estimated 12–18 months minimum with a dedicated team of senior WebRTC engineers
- 100ms — prebuilt React SDK with hooks, built-in chat, screen sharing, recording, captions, and virtual backgrounds out of the box
Decision
I chose 100ms for the fastest path to a working product. Its prebuilt React SDK matched our Next.js stack cleanly and reduced initial development time significantly compared to Agora or Twilio. We built a working POC in 2 days and shared it with the client — they could see all capabilities live: screen sharing, recording, participant data, captions, chat. No low-level WebRTC management required.
Webhook-Driven Auto-Recording Instead of 100ms Legacy Trigger
Situation
The requirement was that if a host enables auto-recording during stream setup, recording should start automatically the moment the stream begins — no manual action needed from anyone.
Options Considered
- Use 100ms's legacy built-in option to auto-start recording at room creation time
- Listen to 100ms's stream-started webhook event and trigger recording through their current recording API
Decision
I went with the webhook approach. 100ms had a legacy option to auto-start recording at room creation, but their recommended path for the latest recording style was the webhook. This kept us on the actively maintained API rather than a legacy feature they were moving away from.
Microservices Architecture with NestJS and Turborepo Monorepo
Situation
Vonza was a large platform with years of feature additions, but the existing codebase had accumulated enough technical debt that adding new features had become slow and risky. The stakeholders came to me wanting a scalable, readable architecture they could build on for years — and streaming was the starting point.
Options Considered
- Continue building new features into the existing monolith — faster to start, but carrying the same debt forward and blocking future velocity
- Introduce microservices with NestJS on the backend and a Turborepo monorepo on the frontend, isolating each feature into its own service and app
Decision
I recommended the microservices and monorepo approach. Each feature — streaming, affiliate, signaturely — lives in its own isolated backend service and frontend app, with a shared packages layer for reusable code. The decision paid off immediately: two more features were built using the same structure after streaming shipped, without disrupting existing services. Failures in one service don't cascade into others.
Features
Three Stream Room Types
Hosts can create scheduled streams (pre-planned sessions with a set time), instant streams (go live immediately), and personal rooms (persistent links for recurring sessions).
Shareable Links with Optional Password Protection
Each room generates a shareable link that can optionally be password-protected, giving the host full control over who can join.
Email-Based Invite System
Hosts can invite guests by email with role-scoped access, controlling what each participant can do inside the session.
Auto-Recording
If enabled at setup, recording starts automatically the moment the stream begins via a webhook-driven flow. Hosts can also toggle recording on or off manually during a live session.
Guest Join Flow with Access Validation
Guests go through a validation flow based on how they were invited — public link, password-protected link, or email invite — all handled through a single unified access model.
In Action
Create new stream
Stream with host
My Role
I led a team of four engineers as the technical lead, working primarily at the architecture level — evaluating streaming service providers, designing the microservices boundary, defining the data schema, and establishing the Turborepo monorepo structure for the frontend. Day-to-day implementation was carried out by the team.
Tech Stack
Outcome
The initial milestone was delivered in one month. The client reviewed it with their team and the feedback was strong. The architecture decision proved its value quickly — two additional features (affiliate marketing and a document signing integration) were built on the same microservices and monorepo structure without affecting the streaming module.