DEV Community

Cover image for 🔥 From Zero to Serverless: Building a Real-Time Chat App with Deno, WebSockets, and No Backend
Yevhen Kozachenko 🇺🇦
Yevhen Kozachenko 🇺🇦

Posted on • Originally published at ekwoster.dev

🔥 From Zero to Serverless: Building a Real-Time Chat App with Deno, WebSockets, and No Backend

🔥 From Zero to Serverless: Building a Real-Time Chat App with Deno, WebSockets, and No Backend

Imagine building a real-time chat application where there's no traditional backend—no Express, no database, not even a VM running 24/7. Sounds crazy? Welcome to the world of Deno and serverless WebSockets.

In this article, we’re diving deep into a lesser-known yet powerful use case: spinning up a real-time chat system using Deno Deploy, native WebSockets, and entirely stateless architecture. This is not your normal CRUD + PostgreSQL tutorial—this is an architectural eye-opener for modern developers.


🤯 Why This Setup Matters

Most chat apps are built on socket.io with Express or Nest.js, tethered to a server and a database with sessions, user tokens, etc. But what if:

  • You didn’t need an always-on server?
  • Your app scaled instantly under traffic?
  • You never paid for idle?
  • You didn’t even need a database for transient messages?

You can use Deno Deploy + WebSockets + Edge broadcast channels to build a chat app that’s instantly scalable and runs at the edge. Welcome to the serverless revolution.


🛠️ Tech Stack

  • Deno Deploy - Serverless JavaScript/TypeScript runtime.
  • Native WebSockets - Real-time communication.
  • BroadcastChannel API - Native API to synchronise between edge locations (yes, stateless side channel!)
  • Vanilla HTML/JS frontend

🎯 What We'll Build

A real-time chat app:

  • Send/receive messages instantly
  • No backend
  • Client-side rendered
  • Completely stateless (no DB!)

⚡ Quick Preview

chat-demo


📦 Getting Started

1. Project Structure

chat-app/
├── main.ts # Deno serverless handler
└── static/
    └── index.html # UI
Enter fullscreen mode Exit fullscreen mode

🧠 The Magic in main.ts

// main.ts
import { serve } from "https://deno.land/std@0.202.0/http/server.ts";

// Broadcast channel to relay messages across edge instances
const channel = new BroadcastChannel("global-chat");

serve((req) => {
  const { socket, response } = Deno.upgradeWebSocket(req);

  socket.onopen = () => {
    console.log("Client connected");
  };

  socket.onmessage = (event) => {
    const msg = event.data;
    // Broadcast to all edges / users
    channel.postMessage(msg);
  };

  // Relay messages to connected clients
  channel.onmessage = (e) => {
    socket.send(e.data);
  };

  socket.onclose = () => console.log("Client disconnected");

  return response;
});
Enter fullscreen mode Exit fullscreen mode

Deploy it Now

You can instantly deploy this with:

deno deploy --project=chat-app main.ts
Enter fullscreen mode Exit fullscreen mode

💻 Frontend (index.html)

<!-- static/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Deno Chat</title>
  <style>
    body { font-family: sans-serif; margin: 1rem; }
    #messages { height: 300px; overflow-y: scroll; border: 1px solid #ccc; padding: 1rem; }
    input { width: 80%; }
  </style>
</head>
<body>
  <h2>💬 Deno Real-Time Chat</h2>
  <div id="messages"></div>
  <input id="messageInput" placeholder="Type a message..." />
  <button onclick="sendMessage()">Send</button>

  <script>
    const ws = new WebSocket("wss://your-deno-project.deno.dev");
    const messagesDiv = document.getElementById("messages");

    ws.onmessage = (event) => {
      const el = document.createElement("div");
      el.textContent = event.data;
      messagesDiv.appendChild(el);
      messagesDiv.scrollTop = messagesDiv.scrollHeight;
    };

    window.sendMessage = () => {
      const input = document.getElementById("messageInput");
      if (input.value) ws.send(input.value);
      input.value = "";
    };
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

🧪 Curious Edge Tech: The Broadcast Channel

Deno Deploy has support for BroadcastChannel, which is essentially a real-time communication tunnel across Deno's global edge locations.

This is the key. Since your WebSocket connections might hit different edge servers, a local in-memory relay won’t work. But with BroadcastChannel, messages get broadcast to all connected edge nodes, creating true global state synchronization—without Redis or databases.


🌍 Real-Life Use Cases

  • Live score update apps
  • Real-time dashboards
  • Multiplayer browser games
  • Temporary real-time community chats (like Reddit AMAs)

🤔 What’s Missing (and Why That’s Okay)

This app is great for use cases where message history is ephemeral. Think more WhatsApp group live than Slack workspace. If you need persistence:

  • Add Supabase/PlanetScale/Fauna for DB storage.
  • Store messages on the client with IndexedDB.

But if your messages can vanish after reload, you just built a beautiful stateless chat system, instantly scalable, with no backend code beyond a single file. Pretty cool, huh?


🚀 Next Steps

  • Deploy this app on https://deno.com/deploy
  • Add localStorage to cache messages client-side
  • Add usernames, emojis, and typing indicators
  • Add authentication using Deno KV (Redis-like storage)

🧠 Lessons Learned

✅ WebSockets are amazing — and native everywhere now

✅ Deno Deploy lets you build at the edge without thinking about servers

✅ Broadcast Channel turns stateless services into networked ones

✅ Simplicity wins — one TypeScript file > 4 services


📚 Resources

  • Deno Deploy
  • BroadcastChannel API
  • Deno WebSocket Docs

If you're still binding socket.io to Express in 2024, you're working too hard. Embrace the edge. 🧠


💌 Found this cool or have questions? Email me or drop a DM on Twitter @edgechad 🤘


💡 If you need this done – we offer fullstack development services! Check it out here

Top comments (0)