Docs Self-Managed Develop Build a Chat Room Application Cloud Node.js This is documentation for Self-Managed v23.2, which is no longer supported. To view the latest available version of the docs, see v24.2. Build a Chat Room Application with Redpanda Cloud and Node.js Create a basic chat room application with Redpanda Cloud and Kafka clients developed with kafkajs. This tutorial describes how to: Start a Redpanda cluster to store and stream chat room messages. Write a client application in TypeScript to produce and consume chat room messages. Build and run multiple clients to exchange chat messages streamed through Redpanda Cloud. Prerequisites Install Node.js for your platform. Redpanda Cloud environments use certificates signed by Let’s Encrypt. Most programming languages will Load their root certificate authority (CA), ISRG Root X1, by default so you shouldn’t need to provide a custom CA. Set up Redpanda Cloud Complete the Redpanda Cloud Quickstart before continuing. This tutorial expands on the quickstart. Set up your environment Create and set your working directory to the project folder, chat-room: mkdir chat-room cd chat-room Generate the package.json file: npm init -y Install the required dependencies: npm i -D typescript npm i -D @types/node npm i kafkajs npm i uuid npm i -D @types/uuid Generate a tsconfig.json file: node_modules/typescript/bin/tsc --init In chat-room/, create a src/ directory for source files: mkdir src Create a topic You need a topic named chat-room for both Redpanda and the client to use to store chat room messages. If you completed the Redpanda Cloud Quickstart, this topic already exists in your cluster. Verify that the chat-room topic exists in your cluster by listing all topics: rpk topic list --tls-enabled Output: NAME PARTITIONS REPLICAS chat-room 1 1 If the topic doesn’t exist yet, use rpk to create a chat-room topic: rpk topic create chat-room --tls-enabled Output: TOPIC STATUS chat-room OK Confirm that the topic exists on the client side The client may not always know that the topic exists. You can verify that it exists and create it if not. In chat-room/ create a source file called src/admin.ts with the following content. Replace the placeholders with the same values that you used in the Redpanda Cloud Quickstart. src/admin.ts import { Kafka } from "kafkajs"; const redpanda = new Kafka({ brokers: ["<bootstrap-server-address>"], ssl: { }, sasl: { mechanism: "scram-sha-256", username: "redpanda-chat-account", password: "<password>" } }); const admin = redpanda.admin(); export async function createTopic( topic: string, partitions?: number, replicas?: number ) { await admin.connect(); const existingTopics = await admin.listTopics(); if (!existingTopics.includes(topic)) { await admin.createTopics({ topics: [ { topic: topic, numPartitions: partitions ? partitions : 1, replicationFactor: replicas ? replicas : 1, }, ], }); } await admin.disconnect(); } Create a producer A client needs a producer to publish chat-room topic messages. To create a producer for the client, in chat-room/ create a source file src/producer.ts with the following content. Replace the placeholders with the same values that you used in the Redpanda Cloud Quickstart. src/producer.ts import { Kafka } from "kafkajs"; const redpanda = new Kafka({ brokers: ["<bootstrap-server-address>"], ssl: { }, sasl: { mechanism: "scram-sha-256", username: "redpanda-chat-account", password: "<password>" } }); const producer = redpanda.producer(); export async function getConnection(user: string) { try { await producer.connect(); return async (message: string) => { await producer.send({ topic: "chat-room", messages: [{ value: JSON.stringify({ message, user }) }], }); }; } catch (error) { console.error("Error:", error); } } export async function disconnect() { try { await producer.disconnect(); } catch (error) { console.error("Error:", error); } } You now have a working producer that sends strings entered by the user to the chat-room topic. Messages are sent as JSON encoded strings here, but keep in mind that the producer only sends buffers, so you can encode the messages however you like. Create a consumer A client needs a consumer to receive chat-room topic messages. To create a consumer for the client, in chat-room/ create a source file src/consumer.ts with the following content. Replace the placeholders with the same values that you used in the Redpanda Cloud Quickstart. src/consumer.ts import { Kafka } from "kafkajs"; import { v4 as uuidv4 } from "uuid"; const redpanda = new Kafka({ brokers: ["<bootstrap-server-address>"], ssl: { }, sasl: { mechanism: "scram-sha-256", username: "redpanda-chat-account", password: "<password>" } }); const consumer = redpanda.consumer({ groupId: uuidv4() }); export async function connect() { try { await consumer.connect(); await consumer.subscribe({ topic: "chat-room" }); await consumer.run({ eachMessage: async ({ topic, partition, message }) => { const formattedValue = JSON.parse( (message.value as Buffer).toString() ); console.log(`${formattedValue.user}: ${formattedValue.message}`); }, }); } catch (error) { console.error("Error:", error); } } export async function disconnect() { try { await consumer.disconnect(); } catch (error) { console.error("Error:", error); } } You now have a consumer that reads all messages from the chat-room topic and prints them to the console. You can start as many consumer groups as you like, but remember that each group reads a message only once, which is why the example is using a generated UUID for the group ID. Because the eachMessage() function automatically commits on a heartbeat interval, there is no commit() method or auto-commit configuration in the code. Create a client application The client needs an application that creates the topic, producer, and consumer and implements the chat logic. To create a client application, in chat-room/ create a source file src/index.ts with the following content. src/index.ts import * as readline from "node:readline"; import * as Admin from "./admin"; import * as Producer from "./producer"; import * as Consumer from "./consumer"; const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); async function start() { const topic = "chat-room"; console.log(`Creating topic: ${topic}`); await Admin.createTopic(topic); console.log("Connecting..."); await Consumer.connect(); rl.question("Enter user name: \n", async function (username) { const sendMessage = await Producer.getConnection(username); if (sendMessage) { console.log("Connected, press Ctrl+C to exit"); rl.on("line", (input) => { readline.moveCursor(process.stdout, 0, -1); sendMessage(input); }); } else { console.error("Failed to initialize sendMessage function"); } }); } start(); process.on("SIGINT", async () => { console.log('Closing app...'); try { await Producer.disconnect(); await Consumer.disconnect(); rl.close(); } catch (err) { console.error('Error during cleanup:', err); process.exit(1); } finally { console.log('Cleanup finished. Exiting'); process.exit(0); } }); Build and run the application Build the client chat application, run it from multiple client terminals, and chat between the clients. From chat-room/, build the client application: node_modules/typescript/bin/tsc src/index.ts Open at least two terminals, and for each terminal: Run the client application: node src/index.js When prompted with Enter user name:, enter a unique name for the chat room. Use the chat application: enter a message in a terminal, and verify that the message is received in the other terminals. For example: Enter user name: Alice Connected, press Ctrl+C to exit Alice: Hi, I'm Alice Bob: Hi Alice, I'm Bob, nice to meet you Next steps This is a basic example of a chat room application. You can improve this application by implementing additional features and components, such as: A user interface to make it more interactive and user-friendly. A user registration and login system to authenticate users before they can access the chat room. Rate limiting and other measures to prevent spamming and abuse in the chat room. Suggested reading For additional resources to help you build stream processing applications that can aggregate, join, and filter your data streams, see: Redpanda University Redpanda Blog Resources Back to top × Simple online edits For simple changes, such as fixing a typo, you can edit the content directly on GitHub. Edit on GitHub Or, open an issue to let us know about something that you want us to change. Open an issue Contribution guide For extensive content updates, or if you prefer to work locally, read our contribution guide . Was this helpful? thumb_up thumb_down group Ask in the community mail Share your feedback group_add Make a contribution Java Python