Popii is a convention-first Discord bot framework built for the Bun runtime. It works like a modern web framework: drop a file in the right folder, and it gets picked up automatically. No manual registration, no restarts during development.
bunx popii init
The interactive wizard walks you through naming your bot, picking plugins, and configuring your .env. A browser window opens so you can paste your token and select intents visually.
cd my-bot
bun run dev
Your bot is now live with hot-module replacement enabled. Save any file — command, event, middleware — and changes apply immediately without a Discord disconnect.
my-bot/
├── src/
│ ├── index.ts # entry point — calls popiiClient()
│ ├── commands/ # one file per command (auto-registered)
│ ├── events/ # one file per Discord event (auto-registered)
│ ├── snaps/ # persistent component handlers (auto-registered)
│ ├── middlewares/ # global middleware (auto-registered, sorted alphabetically)
│ └── tasks/ # scheduled background tasks (auto-registered)
├── .env
└── package.json
src/index.ts
import { popiiClient } from "popii";
const client = popiiClient({
token: process.env.DISCORD_TOKEN!,
});
client.start();
src/commands/ping.ts
import { command } from "popii";
export default command({
name: "ping",
description: "Replies with Pong!",
async do(pop) {
await pop.reply(`Pong! ${pop.client.discord.ws.ping}ms`);
}
});
That's the entire setup. Popii finds ping.ts, registers /ping as a slash command, and starts listening.