All case studies
Nova Dynamic Media·Senior Full-Stack & Cloud Engineer

From IoT Core to AppSync

Re-platforming real-time audience interaction for scale

AppSyncGraphQLDynamoDBLambdaWebSocketsAmazon IVS
50+
enterprise live events delivered on AppSync
High-concurrency
absorbed peak spikes — thousands voting & asking at once
Zero dropped messages
reconnects read true state straight from DynamoDB
In-sync
slides, captions & engagement locked to the IVS low-latency stream
Faster shipping
built-in resolvers + validation cut backend boilerplate
Faster sync
live updates land in fractions of a second

Options on the table

Stay on IoT Core / MQTT
Heavy client connections, no schema, and state decoupled from delivery — race conditions on reconnect/refresh.
Self-managed WebSocket layer
Would own scaling, auth, reconnection and schema ourselves — too much undifferentiated heavy lifting.
AWS AppSync + GraphQL
Native subscriptions over WebSockets, one strongly-typed graph for mutations/queries/subscriptions, direct DynamoDB + Lambda integration.

Architecture at a glance

From IoT Core to AppSync — architecture diagram

Background

Nova Dynamic Media runs large-scale enterprise live events — webcasts, conferences and hybrid productions where the audience isn't just watching, they're participating. During a session, attendees submit and upvote questions, answer live polls and quizzes, respond to surveys, and follow slides that advance in lockstep with the speaker, all on top of an ultra-low-latency Amazon IVS video stream.

Every one of those interactions has to reach thousands of devices in near real time, and stay correct when someone's phone drops off the venue Wi-Fi and reconnects. The original platform delivered this real-time layer with AWS IoT Core over MQTT — a Pub/Sub design borrowed from the IoT world. It worked at small scale, but as audiences and feature complexity grew, the seams started to show.

Why IoT Core fell short

IoT Core is purpose-built for device telemetry — millions of sensors publishing small messages. A user-facing, interactive event is a different problem, and three mismatches kept surfacing:

  • Heavy client connections: Web browsers had to hold an MQTT client connection open. On mobile and flaky venue networks that meant extra weight, reconnection edge cases, and battery/perf overhead just to receive a poll update.
  • No schema, hand-rolled everything: Raw Pub/Sub has no strict data contract, so the team manually handled serialization, payload validation and parsing on both the backend and every client — error-prone boilerplate that grew with each new feature.
  • Delivery without state: MQTT delivers a message but stores nothing. To show the current poll result or Q&A thread to someone who just refreshed, the app had to separately query DynamoDB — racing the live Pub/Sub stream against the state database and occasionally showing stale or missed data.

Why AppSync

AWS AppSync collapses the real-time problem and the state problem into one managed GraphQL backend, which is exactly the shape of this domain.

Subscriptions ride standard WebSockets under the hood — no MQTT wrapper for the browser to manage. A single strongly-typed schema unifies mutations (writing data), queries (fetching current state) and subscriptions (listening for live updates), so validation and parsing come for free. And AppSync resolves directly against DynamoDB and Lambda, so one operation can persist a change and broadcast it to every connected attendee in a single round-trip.

We considered building our own WebSocket layer, but that meant owning scaling, auth, reconnection and schema ourselves — undifferentiated heavy lifting AppSync already does well.

How we re-engineered the pipeline

The migration turned a fragmented messaging system into one strongly-typed real-time data graph, with DynamoDB as the single source of truth and AppSync owning the WebSocket fan-out. Design goals: keep the hot path resolver-only (no Lambda latency), scope every broadcast to its event, and make state idempotent so reconnects and retries can't corrupt it.

  • Schema & subscription filtering: One typed schema models the domain — mutations (publishPoll, advanceSlide, submitQuestion, upvote), queries (getEventState), and subscriptions (onEventUpdate(eventId)). AppSync enhanced subscription filters bind each subscription to its eventId, so a mutation fans out only to that event's devices instead of every connected client.
  • Resolver-only hot path: Most operations use AppSync resolvers (VTL/JS) mapped straight to DynamoDB — no Lambda in the critical path, removing cold-start and invocation latency. Multi-step flows use pipeline resolvers; Lambda data sources are reserved for genuinely complex cases.
  • DynamoDB single-table design: A single table with composite keys (PK EVENT#{id}, SK POLL#/QUESTION#/SLIDE#) serves every access pattern, with GSIs for upvote-ordered question feeds. Atomic counters (ADD) handle upvotes; conditional writes give optimistic concurrency so duplicate or out-of-order mutations can't clobber state.
  • Mutation→subscription loop: A slide change is one mutation: the resolver persists new state to DynamoDB and AppSync broadcasts the result to every subscribed device in fractions of a second — one round-trip, no separate publish step, no drift between what's stored and what's shown.
  • Grounded state on reconnect: Because the store sits directly behind the graph, a device back from a network drop just runs getEventState and gets the canonical current state — no fragile replay of a Pub/Sub stream it missed offline.
  • Tiered auth & Mission Control: Cognito authorizes moderators with field-level rules (only staff can publish/advance); attendees subscribe under a read-only tier. Mission Control is the single surface issuing those privileged mutations — live upvoting, nested replies, and the speaker teleprompter channel, all kept in step with the ultra-low-latency Amazon IVS stream.

The impact

Across 50+ enterprise live events, the AppSync architecture delivered wins that were both technical and felt by the business:

  • High-concurrency scale: Absorbed massive spikes when thousands of attendees voted or asked questions at the same moment during peak sessions.
  • Correctness by design: With DynamoDB behind the GraphQL interface, state is always grounded — a brief disconnect no longer means lost or stale data; the client just re-fetches the truth.
  • Perfect sync: Slides, live captions and engagement elements stay locked to the ultra-low-latency IVS stream, so what the audience sees and what they interact with never drift apart.
  • Developer velocity: Built-in resolvers and schema validation removed a layer of backend boilerplate, so the team shipped new event features faster.

What I took away

Pick the abstraction that matches your domain. MQTT shines for devices; interactive event UX maps far more cleanly onto GraphQL — subscriptions for delivery plus DynamoDB-backed queries for state kills the live-stream-vs-database race condition and cuts backend boilerplate.
Want the deeper architecture behind this? Let's talk.
Get in touch