Skip to content
IRC-CodingIRC-Coding
ircbotprogrammingpythonnodejsgorustframeworktutorialguide

IRC Bot Development: Frameworks for Python, Node.js, Go & Rust

Complete IRC bot development guide with pydle, irc-framework, go-ircevent, and Rust irc crate. From basics to production.

I

IRC-Coding Team

8 min read
IRC Bot Development: Frameworks for Python, Node.js, Go & Rust

Building an IRC Bot: Frameworks for Python, Node.js, Go & Rust

In this “In a Nutshell Tutorial,” I’ll show you how quickly you can write a small IRC bot in different languages using various frameworks.

Why Python?

Python is one of the most popular programming languages today and offers countless libraries for text processing. I work professionally with Python frameworks like FastAPI and enjoy integrating systems like this.

Why Node.js?

On the server side, Node.js is modern and its integration fits naturally into many JavaScript frameworks. If you code regularly, you’ll find Node.js hard to avoid.

Why Go?

Go excels at IRC bots thanks to built-in concurrency features (Goroutines) and straightforward network programming. The compiled binaries are small and fast—ideal for bots that need to run 24/7.

Why Rust?

Whatever project comes up, implementing it with Rust is always worth considering. So here’s a quick Rust implementation to show how straightforward it can be. Rust delivers memory safety without a garbage collector—perfect for long-lived bots.

The Core Principles of an IRC Bot

To build a solid foundation or find the right starting point, it helps to map out the core tasks an IRC bot needs to handle. Rather than UML diagrams or flowcharts, let’s use a simple task list.

What all IRC bots do at their core:

  • Establish a TCP connection to the IRC server
  • Set a nickname
  • Handle authentication (NickServ / SASL) if needed
  • Join channels
  • Read messages (events)
  • Respond to PRIVMSG
  • Send replies as needed

Of course, you can extend the functionality endlessly. In this guide we’ll also look at a plugin system and async methods.

There are many tutorials that explain everything from scratch, but this “In a nutshell tutorial” assumes you have the basics down and jumps straight into installations and requirements.

Python – irc (simplest entry point)

Installation

pip install irc

Minimal Bot

import irc.bot

class MyBot(irc.bot.SingleServerIRCBot):
    def __init__(self):
        server = [("irc.IRC-Mania.de", 6667)]
        nickname = "MyPyBot"
        irc.bot.SingleServerIRCBot.__init__(self, server, nickname, nickname)

    def on_welcome(self, connection, event):
        connection.join("#ircmania")

    def on_pubmsg(self, connection, event):
        msg = event.arguments[0]
        if msg == "!ping":
            connection.privmsg(event.target, "pong")

if __name__ == "__main__":
    MyBot().start()

What’s happening here?

  • on_welcome → join channel
  • on_pubmsg → messages in the channel
  • simple string logic for commands

You should grasp the pattern here. Now you can explore frameworks—and they make things even simpler. Python offers plenty of suitable options.

Python – irc3 (modern & modular)

irc3 is a modern, plugin-based IRC framework for Python. It includes built-in command handlers, automatic reconnection logic, and a clean plugin architecture. Perfect for larger bots with lots of features.

Installation

pip install irc3

Bot

import irc3
from irc3.plugins.command import command

@irc3.plugin
class Plugin:
    def __init__(self, bot):
        self.bot = bot

    @command
    def ping(self, mask, target, args):
        """!ping command"""
        self.bot.privmsg(target, "pong")

config = dict(
    nick='MyIrc3Bot',
    autojoins=['#ircmania'],
    host='irc.IRC-Mania.de',
    port=6667,
    includes=['irc3.plugins.core', __name__],
)

irc3.IrcBot(**config).run()

Advantage: plugins and commands out of the box

Python – pydle (async & modern)

pydle is a modern, async-based IRC framework. The key advantage over irc3 is native async/await support, which is ideal for I/O-intensive bots. pydle is lighter and more flexible, though it has fewer built-in features than irc3.

Installation

pip install pydle

Bot

import pydle

class MyBot(pydle.Client):
    async def on_connect(self):
        await self.join('#ircmania')

    async def on_message(self, target, source, message):
        if message == "!ping":
            await self.message(target, "pong")

client = MyBot("MyPydleBot")
client.run("irc.IRC-Mania.de", tls=False)

Node.js – irc-framework

Node.js is excellent for IRC bots thanks to its event-driven architecture. The non-blocking I/O model maps perfectly to IRC’s message system. irc-framework is the most popular library, offering excellent reconnection features and a plugin system.

Installation

npm install irc-framework

Bot

const IRC = require('irc-framework');

const bot = new IRC.Client();

bot.connect({
    host: 'irc.IRC-Mania.de',
    port: 6667,
    nick: 'MyNodeBot'
});

bot.on('registered', () => {
    bot.join('#ircmania');
});

bot.on('message', (event) => {
    if (event.message === '!ping') {
        bot.say(event.target, 'pong');
    }
});

Go – go-ircevent

Installation

go get github.com/thoj/go-ircevent

Bot

package main

import (
    "github.com/thoj/go-ircevent"
    "fmt"
)

func main() {
    bot := irc.IRC("MyGoBot", "MyGoBot")
    
    bot.AddCallback("001", func(e irc.Event) {
        bot.Join("#ircmania")
    })
    
    bot.AddCallback("PRIVMSG", func(e irc.Event) {
        if e.Message() == "!ping" {
            bot.Privmsg(e.Arguments[0], "pong")
        }
    })
    
    err := bot.Connect("irc.IRC-Mania.de:6667")
    if err != nil {
        fmt.Println(err)
        return
    }

    bot.Loop()
}

Rust – irc crate

Rust is a solid choice for IRC bots since it provides memory safety without garbage collection. This means Rust bots are reliable and stable over the long term.

Installation

cargo add irc

Bot

use irc::client::prelude::*;

fn main() {
    let config = Config {
        nickname: Some("MyRustBot".to_owned()),
        server: Some("irc.IRC-Mania.de".to_owned()),
        channels: vec!["#ircmania".to_owned()],
        ..Default::default()
    };

    let mut client = Client::from_config(config).unwrap();
    client.identify().unwrap();

    for message in client.stream().unwrap() {
        if let Ok(message) = message {
            if let Command::PRIVMSG(_, ref msg) = message.command {
                if msg == "!ping" {
                    let _ = client.send_privmsg("#ircmania", "pong");
                }
            }
        }
    }
}

Integrating IRC Bots into Python Web Frameworks

Absolutely—you can integrate IRC bots beautifully into modern Python web frameworks. This opens exciting possibilities for web applications with chat integration.

Overview: Python Web Frameworks for IRC Bots

FastAPI

Suitability: Excellent

  • Asynchronous API backend
  • WebSocket support for live chat
  • Automatic API documentation
  • Perfect for microservices

Streamlit

Suitability: Very good

  • Rapid dashboard development
  • No frontend knowledge required
  • Live updates with session state
  • Ideal for prototypes

Django

Suitability: Good

  • Full-featured web framework
  • Admin interface for bot management
  • ORM for message history
  • Real-time features with Channels

Flask

Suitability: Good

  • Lightweight and flexible
  • Simple integration
  • Socket.IO for real-time
  • Minimalist approach

Fastify

Suitability: Very good

  • High-performance API
  • Async/await support
  • Plugin system
  • WebSocket integration

Sanic

Suitability: Good

  • Asynchronous framework
  • WebSocket support
  • High-speed performance
  • Python 3.6+ features

FastAPI Integration (perfect… fast)

from fastapi import FastAPI, WebSocket
import asyncio
import threading
from irc.bot import SingleServerIRCBot

app = FastAPI()

class IRCBot(SingleServerIRCBot):
    def __init__(self):
        server = [("irc.IRC-Mania.de", 6667)]
        nickname = "FastAPIBot"
        super().__init__(server, nickname, nickname)
        self.messages = []

    def on_pubmsg(self, connection, event):
        msg = event.arguments[0]
        self.messages.append({
            "channel": event.target,
            "user": event.source.split("!")[0],
            "message": msg,
            "timestamp": asyncio.get_event_loop().time()
        })

irc_bot = IRCBot()
threading.Thread(target=irc_bot.start, daemon=True).start()

@app.get("/messages")
async def get_messages():
    return {"messages": irc_bot.messages[-20:]}

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        await websocket.send_json({"messages": irc_bot.messages[-5:]})
        await asyncio.sleep(1)

Streamlit Integration (very good)

import streamlit as st
import threading
from irc.bot import SingleServerIRCBot

class StreamlitIRCBot(SingleServerIRCBot):
    def __init__(self):
        super().__init__([("irc.IRC-Mania.de", 6667)], "StreamlitBot", "StreamlitBot")
        if 'messages' not in st.session_state:
            st.session_state.messages = []

    def on_pubmsg(self, connection, event):
        st.session_state.messages.append({
            "channel": event.target,
            "user": event.source.split("!")[0],
            "message": event.arguments[0],
            "time": time.strftime("%H:%M:%S")
        })

if 'irc_bot' not in st.session_state:
    st.session_state.irc_bot = StreamlitIRCBot()
    threading.Thread(target=st.session_state.irc_bot.start, daemon=True).start()

st.title("IRC Bot Dashboard")
for msg in reversed(st.session_state.messages[-10:]):
    st.chat_message(msg["user"]).write(f"**{msg['channel']}**: {msg['message']}")

Django Integration (good)

# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from irc.bot import SingleServerIRCBot
import threading

class DjangoIRCBot(SingleServerIRCBot):
    def __init__(self):
        super().__init__([("irc.IRC-Mania.de", 6667)], "DjangoBot", "DjangoBot")

django_bot = DjangoIRCBot()
threading.Thread(target=django_bot.start, daemon=True).start()

@csrf_exempt
def send_message(request):
    if request.method == 'POST':
        channel = request.POST.get('channel')
        message = request.POST.get('message')
        django_bot.connection.privmsg(channel, message)
        return JsonResponse({'status': 'sent'})

Benefits of Framework Integration

  • Web interface: Control the bot from your browser instead of the command line
  • API endpoints: Other applications can communicate with your bot
  • Data persistence: Store chat history in databases
  • Monitoring: Live dashboards to track bot activity
  • Multi-user access: Multiple users can control the bot simultaneously
  • Real-time features: WebSocket integration for live updates

I hope these quick introductions spark your curiosity about IRC bots and Internet Relay Chat again. This site exists for exactly that reason. You’ll find detailed beginner tutorials here and on IRC-Mania.de.

What All Bots Have in Common

At the end of the day, every programming language follows the same recipe—just sometimes with different ingredients:

Regardless of language:

connectTCP connection to IRC server
registerNick + User
joinEnter a channel
listenRead events
reactRespond to PRIVMSG

Typical IRC Bot Features (next level)

Once you move beyond the basics, you’ll encounter these classics:

🔹 Moderation

  • Kick / Ban / mute
  • Word filtering
  • User management

🔹 Logging Bot

  • Saves channel history
  • Search functionality
  • Statistics

🔹 API Bot

  • !weather Berlin
  • GitHub / CI status
  • External integrations

🔹 Anti-Spam

  • Flood detection
  • Rate limiting
  • Pattern matching

🔹 Reconnect Logic Important: IRC connections drop frequently!

We started with simple functions above. If you want to build something larger, it’s worth spending time on a basic architectural foundation. You don’t need formal class diagrams or use-case models, but having a clear direction will save you headaches later.

I’ll show you a production-ready IRC bot architecture, plus how to cleanly separate multi-channel handling and async/threading concerns so your bot doesn’t crash after two days or lose messages.

Production-Ready IRC Bot Architecture

The Target

A stable IRC bot needs clear separation of concerns:

┌─────────────────┐ │ IRC Client │ ← Connection to server └─────────┬───────┘ │ ┌─────────▼───────┐ │ Event Dispatcher│ ← Routes events └───────┬─┬───────┘ │ │ ┌───────▼─▼───────┐ │ Plugin System │ ← Features └─────────────────┘ │ ┌────────▼─┐ ┌────▼────────┐ │ Plugin A │ │ Plugin B │ ← Features └──────────┘ └─────────────┘

Architecture

bot/
 ├── core.py        (IRC client)
 ├── dispatcher.py  (event routing)
 ├── plugins/
     ├── ping.py
     ├── logger.py
     └── admin.py
 └── main.py

Core Bot (async + reconnect)

import pydle
import asyncio

class CoreBot(pydle.Client):
    def __init__(self, nickname, channels):
        super().__init__(nickname)
        self.channels = channels
        self.plugins = []
        self.reconnect_delay = 5

    async def on_connect(self):
        for channel in self.channels:
            await self.join(channel)

    async def on_disconnect(self, expected):
        while True:
            try:
                await self.reconnect()
                break
            except:
                await asyncio.sleep(self.reconnect_delay)

    async def on_message(self, target, source, message):
        for plugin in self.plugins:
            await plugin.handle_message(self, target, source, message)

    def register_plugin(self, plugin):
        self.plugins.append(plugin)

Plugin System

class PingPlugin:
    async def handle_message(self, bot, target, source, message):
        if message == "!ping":
            await bot.message(target, "pong")

Main Runner

from core import CoreBot
from plugins.ping import PingPlugin

bot = CoreBot("MyBot", ["#dev", "#test"])
bot.register_plugin(PingPlugin())

bot.run("irc.libera.chat", tls=False)

Multi-Channel Behavior

This happens automatically:

  • Bot joins #dev and #test
  • Bot responds independently in each channel

Example:

#dev: !ping  -> pong
#test: !ping  -> pong

Threaded Architecture (if you’re not using async)

Alternative approach (traditional, for instance with Python irc lib):

The Problem:

The IRC loop blocks everything, which slows down your plugins.

The Solution:

Worker threads IRC Thread ───► Event Queue ───► Worker Threads

Example pattern:

from queue import Queue
import threading

event_queue = Queue()

def worker():
    while True:
        event = event_queue.get()
        handle_event(event)

threading.Thread(target=worker, daemon=True).start()

IRC callback:

def on_message(msg):
    event_queue.put(msg)

Benefits:

  • The IRC connection stays responsive
  • CPU-intensive tasks don’t block message handling

Production Features (essential for real bots)

1. Auto-Reconnect

async def on_disconnect(self, expected):
    while True:
        try:
            await self.reconnect()
            break
        except:
            await asyncio.sleep(5)

2. Rate Limiting (Flood Protection)

IRC servers will kick you if you send too many messages at once.

import time

last_send = 0

def safe_send(bot, target, msg):
    global last_send
    if time.time() - last_send < 1:
        time.sleep(1)
    bot.message(target, msg)
    last_send = time.time()

3. SASL / NickServ Auth

CAP REQ :sasl
AUTHENTICATE PLAIN

Required for:

  • Reserved nicknames
  • IRC networks like Libera

4. Logging System

async def on_message(self, target, source, message):
    print(f"[{target}] {source}: {message}")

Better approaches:

  • SQLite or PostgreSQL
  • Elasticsearch (for larger bots)

5. Plugin Hot Reload (advanced)

import importlib

def reload_plugin(module):
    importlib.reload(module)

Allows:

  • Updating your bot without disconnecting

Production Architecture (the complete picture)

IRC Server │ Async IRC Client │ ┌───────────▼───────────┐ │ Event Dispatcher │ └───────┬───────┬───────┘ │ │ Plugin System Logger │ Thread Pool (optional heavy tasks)

A production IRC bot is not a script—it’s:

An event-driven async system with plugin architecture and a resilience layer

Back to Blog
Share:

Related Posts