In 2008, our network had a problem. Half the community wanted to stay on IRC. The other half had migrated to Jabber. Nobody wanted to monitor two chat windows. I wrote a crude relay bot in Perl that echoed messages between an IRC channel and a Jabber MUC room. It worked terribly — no nick mapping, no formatting, messages arrived out of order during lag spikes. But people used it, because the alternative was missing half the conversation. Fifteen years later, the bridging problem is mostly solved. The tools are better. The protocols are more numerous. Here's how to connect IRC to everything else without losing your mind.
Why Bridge IRC to Anything
Communities fragment across platforms. Your open-source project has contributors on IRC, Slack, Discord, and Matrix. Your gaming clan split between Discord and IRC. Your company uses Slack but your sysadmin team lives on IRC. Bridging lets everyone talk to each other without switching platforms.
The technical premise is simple: a bot sits in both channels and relays messages. When someone types in the IRC channel, the bot posts it to the Discord channel, and vice versa. The details — nick formatting, threading, file attachments, reactions, message editing — are where things get complicated.
There are three categories of bridge:
- Relay bots: Simple message forwarding. Messages appear as coming from the bot, with the original nick prefixed. This is what Matterbridge does.
- Gateway bots: Create a virtual user for each person on the other side. Messages appear to come from individual users. Matrix's IRC bridge does this.
- Protocol translators: Connect to multiple protocols from a single IRC client. Bitlbee takes this approach.
Each approach has trade-offs. Relay bots are simplest to set up but all messages come from one nick. Gateway bots look native but consume more resources and nick registrations. Protocol translators require each user to run their own instance.
Matterbridge: The Universal Connector
Matterbridge is a single Go binary that bridges between IRC, Discord, Slack, Telegram, Matrix, Mattermost, XMPP, Rocket.Chat, Microsoft Teams, and more. It's the Swiss Army knife of chat bridges. Configuration is a single TOML file.
Install from a release binary (no compilation needed):
# Download the latest release
wget https://github.com/42wim/matterbridge/releases/latest/download/matterbridge-linux-amd64
chmod +x matterbridge-linux-amd64
sudo mv matterbridge-linux-amd64 /usr/local/bin/matterbridge
Here's a configuration that bridges an IRC channel to a Discord channel:
# matterbridge.toml
[irc]
[irc.mynetwork]
Server = "irc.example.net:6697"
UseTLS = true
Nick = "bridge-bot"
Password = "nickserv_password"
NickServNick = "NickServ"
NickServPassword = "nickserv_password"
RemoteNickFormat = "<{NICK}> "
SkipTLSVerify = false
[discord]
[discord.myserver]
Token = "your-discord-bot-token-here"
Server = "123456789012345678" # Discord server ID
RemoteNickFormat = "<{NICK}> "
[[gateway]]
name = "my-bridge"
enable = true
[[gateway.inout]]
account = "irc.mynetwork"
channel = "#general"
[[gateway.inout]]
account = "discord.myserver"
channel = "ID:987654321098765432" # Discord channel ID
Start it:
matterbridge -conf matterbridge.toml
Messages flow both ways. IRC users see Discord messages as <discordnick> message text. Discord users see IRC messages the same way. File attachments from Discord are posted as URLs in IRC. IRC has no file upload concept, so that direction is text-only.
For multiple channel bridges, add more [[gateway]] sections. You can bridge many-to-many — one IRC channel to multiple Discord channels, or three IRC channels across different networks to a single Slack channel.
[bridge] or relay-bot. Register it with NickServ and configure auto-identify. This prevents nick collisions and makes it clear to IRC users that relayed messages come from another platform.Bitlbee: IRC as Your IM Gateway
Bitlbee takes the opposite approach from relay bots. Instead of putting a bot in every channel, Bitlbee is a personal gateway that presents all your chat protocols as IRC. You connect your IRC client to Bitlbee, and your Discord contacts, Slack workspaces, and XMPP contacts appear as IRC buddies.
Install on Debian/Ubuntu:
sudo apt install bitlbee bitlbee-plugin-purple
# purple plugin adds libpurple protocol support (XMPP, etc.)
# Start the service
sudo systemctl enable bitlbee
sudo systemctl start bitlbee
Bitlbee listens on port 6667 by default. Connect your IRC client to localhost:6667. You'll join a control channel called &bitlbee. From there, add accounts:
# In &bitlbee channel:
register mypassword
account add jabber myuser@jabber.org myJabberPassword
account on
# Your XMPP contacts appear as IRC buddies
# Chat with them via /msg or join group chats as IRC channels
For Discord, you need the bitlbee-discord plugin:
# Install from source or package
sudo apt install bitlbee-plugin-discord # if available
# In &bitlbee:
account add discord your@email.com yourpassword
account discord set auto_join true
account on
Bitlbee maps concepts between protocols. A Discord server's channels become IRC channels. A Slack workspace's channels become IRC channels. Direct messages become IRC private messages. It's a clever abstraction that lets you use one IRC client for everything.
The limitation: Bitlbee is per-user. It doesn't bridge channels for a community — it translates protocols for an individual. If you want everyone in your IRC channel to see Discord messages, you need Matterbridge or Matrix, not Bitlbee.
The Matrix-IRC Bridge
The Matrix-IRC bridge (matrix-appservice-irc) is the most sophisticated IRC bridging solution available. It creates a Matrix room that mirrors an IRC channel, with individual Matrix puppets for each IRC user and individual IRC ghosts for each Matrix user. To IRC users, the Matrix people look like normal IRC users. To Matrix users, the IRC people look like normal Matrix users.
This is what Libera.Chat uses for its official Matrix bridge. When you join #libera-chat:matrix.org, you're actually connected to #libera-chat on Libera.Chat's IRC network through this bridge.
Self-hosting the Matrix-IRC bridge requires a Matrix homeserver (Synapse or Dendrite) and the bridge appservice:
# Clone and build the bridge
git clone https://github.com/matrix-org/matrix-appservice-irc.git
cd matrix-appservice-irc
npm install
npm run build
# Generate registration file for your homeserver
node app.js -r -f appservice-registration.yaml -u "http://localhost:9999" -c config.yaml -l bridge_bot
# config.yaml (key sections)
ircService:
servers:
irc.example.net:
port: 6697
ssl: true
botConfig:
nick: "matrixbot"
username: "matrixbot"
membershipLists:
enabled: true
global:
ircToMatrix:
initial: true
incremental: true
matrixToIrc:
initial: true
incremental: true
mappings:
"#general":
roomIds: ["!roomid:your.homeserver.org"]
matrixClients:
userTemplate: "@irc_$NICK:your.homeserver.org"
displayName: "$NICK (IRC)"
ircClients:
nickTemplate: "$DISPLAY[m]"
maxClients: 100
The bridge is resource-hungry compared to Matterbridge. Each bridged IRC user gets a Matrix puppet, and each Matrix user gets an IRC connection. A busy channel with 200 IRC users and 50 Matrix users means the bridge maintains 250 virtual identities. Memory usage scales linearly.
On our test deployment bridging 10 channels, the appservice consumed around 500 MB of RAM. For comparison, Matterbridge doing the same job used under 50 MB. The trade-off is fidelity — Matrix bridge makes cross-platform chat feel native, while Matterbridge makes it feel relayed.
DIY Relay Bots
Sometimes you need something custom. A relay bot that filters certain messages, reformats them, or adds metadata. Writing one from scratch isn't hard if you already know IRC protocol basics.
Here's a minimal Python relay bot that bridges two IRC channels on different networks:
import socket
import threading
import ssl
def irc_connect(server, port, nick, channel, use_tls=True):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if use_tls:
ctx = ssl.create_default_context()
sock = ctx.wrap_socket(sock, server_hostname=server)
sock.connect((server, port))
sock.send(f"NICK {nick}\r\n".encode())
sock.send(f"USER {nick} 0 * :{nick}\r\n".encode())
# Wait for end of MOTD
while True:
data = sock.recv(4096).decode('utf-8', errors='replace')
if 'PING' in data:
sock.send(f"PONG {data.split()[1]}\r\n".encode())
if '376' in data or '422' in data: # RPL_ENDOFMOTD or ERR_NOMOTD
break
sock.send(f"JOIN {channel}\r\n".encode())
return sock
def relay(source_sock, target_sock, source_chan, target_chan, label):
buffer = ""
while True:
data = source_sock.recv(4096).decode('utf-8', errors='replace')
buffer += data
while '\r\n' in buffer:
line, buffer = buffer.split('\r\n', 1)
if line.startswith('PING'):
source_sock.send(f"PONG {line.split()[1]}\r\n".encode())
elif 'PRIVMSG' in line and source_chan in line:
nick = line.split('!')[0][1:]
msg = line.split('PRIVMSG')[1].split(':', 1)[1]
relay_msg = f"PRIVMSG {target_chan} :[{label}/{nick}] {msg}\r\n"
target_sock.send(relay_msg.encode())
# Connect to both networks
sock_a = irc_connect('irc.network-a.net', 6697, 'relay-a', '#bridged')
sock_b = irc_connect('irc.network-b.net', 6697, 'relay-b', '#bridged')
# Relay in both directions
t1 = threading.Thread(target=relay, args=(sock_a, sock_b, '#bridged', '#bridged', 'NetA'))
t2 = threading.Thread(target=relay, args=(sock_b, sock_a, '#bridged', '#bridged', 'NetB'))
t1.start()
t2.start()
This is bare-bones. A production relay needs reconnection logic, flood protection, nick change handling, and probably SASL authentication. But it demonstrates the core concept: read from one socket, write to another.
Operational Issues and Gotchas
Every bridge has failure modes. Here are the ones I've encountered in production:
Message storms. If two bridges accidentally relay the same channel, messages bounce infinitely between them. Each relay bot sees the other bot's message as new and re-relays it. The result is exponential message growth that floods every connected channel in seconds. Always configure bridge bots to ignore messages from other bridge bots — by nick, by hostmask, or by message prefix.
Nick collisions. Matrix-IRC bridges create ghost users on the IRC side. If a Matrix user has the same display name as a registered IRC nick, the ghost collides with the real user. Good bridges add a suffix (like [m]) to prevent this. Configure your suffix carefully and make sure NickServ doesn't kill bridge ghosts.
Formatting loss. IRC has mIRC color codes. Discord has markdown. Matrix has HTML. Bridges translate between these formats with varying success. Bold text usually survives. Colors rarely do. Code blocks are often mangled. Set expectations with your users — bridges relay content, not formatting.
Latency. A relayed message goes: sender's client → sender's server → bridge bot → target platform API → target server → recipient's client. Add network latency at each hop. Conversations feel slightly asynchronous. Fast-paced discussions suffer. Slow, topical discussions work fine.
Choosing the Right Bridge
Here's a decision matrix based on real deployments:
| Scenario | Best Tool | Why |
|---|---|---|
| IRC ↔ Discord (simple) | Matterbridge | Single binary, minimal config |
| IRC ↔ Slack | Matterbridge | Slack API support is solid |
| IRC ↔ Matrix (native feel) | matrix-appservice-irc | Per-user puppeting, best UX |
| IRC ↔ Telegram | Matterbridge | Good Telegram API support |
| Multi-platform (3+) | Matterbridge | One config for all platforms |
| Personal multi-protocol | Bitlbee | Use IRC client for everything |
| Custom filtering/logic | DIY bot | Full control over relay behavior |
For most IRC operators, Matterbridge is the right starting point. It takes 15 minutes to set up, runs as a single process, and supports enough platforms to cover almost any bridging need. If you outgrow it or need native-feeling integration, upgrade to the Matrix bridge.
FAQ
Does Matterbridge support multiple channels simultaneously?
Yes. Define multiple [[gateway]] sections in your config, each mapping a set of channels across platforms. You can bridge dozens of channels with a single Matterbridge instance. Memory usage stays low even with many bridges active.
Can I bridge two IRC networks together?
Yes. Define two IRC accounts in Matterbridge pointing to different servers and bridge their channels through a gateway. Matterbridge, Bitlbee (per-user), or a custom relay bot all work for IRC-to-IRC bridging. This is useful when two communities on different networks want to share a channel without server linking.
Will bridge bots trigger anti-spam on IRC networks?
Potentially. A relay bot posting frequently (relaying a busy Discord or Slack channel) can trigger flood protection. Register the bot's nick with NickServ and ask network staff to exempt it from throttling if needed. On your own network, add the bot's hostmask to the IRCd's exempt list.