Scaffold a production-ready Discord Bot in seconds — not hours.
Quick Start · Generated Output · Features · CLI Reference · generate · Contributing
|
🎛️ Interactive Wizard Beautiful terminal UI powered by @clack/prompts — answers 6 questions and you're done
|
⚡ Components v2 Every generated command uses modern Discord UI — containers, sections, thumbnails — no legacy embeds |
🔘 Full Interaction System Buttons, select menus & modals with auto-loading handlers and typed routing out of the box |
|
🌐 i18n Ready TypeScript-native multi-language support — typed useT() helper, /locale command, zero JSON files
|
🗃️ Database Ready SQLite (better-sqlite3) or PostgreSQL (drizzle-orm) wired from day one with typed schemas |
🛠️ generate Add commands, events, buttons, modals, services & more to an existing project with one command |
# No install needed — always uses latest version
npx discgen-cli my-bot
# Or install globally
npm install -g discgen-cli
discgen-cli my-botRequires Node.js >= 24. Checked on startup — exits with a clear error if too old.
npx discgen-cli my-botThe wizard asks you 7 questions and scaffolds everything — including CI/CD, a logger, env validation, embed helpers, a paginator, and complete component interaction routing.
# Let the wizard ask for the name
npx discgen-cli
# Preview every file that would be written — nothing touches the disk
npx discgen-cli my-bot --dry-run
# Write into a custom folder while keeping the package name
npx discgen-cli my-bot --output ./apps/bots/my-bot
# Skip wizard entirely with a preset
npx discgen-cli my-bot --template basic
npx discgen-cli my-bot --template moderation
npx discgen-cli my-bot --template full
# Show available presets, features, databases, and generate types
npx discgen-cli list┌ discgen-cli — Scaffold a Discord Bot in seconds
│
◇ Project name
│ my-bot
│
◇ Command type
│ Slash Commands
│
◆ Select features
│ ◼ Moderation ◼ Utility ◼ Components ◼ i18n ◻ Fun ◻ Economy ◻ Music
│
◇ Database
│ SQLite
│
◇ Package manager
│ npm (detected)
│
◇ Initialize a git repository?
│ Yes
│
◇ Install dependencies?
│ Yes
│
◒ Scaffolding project...
◒ Installing dependencies with npm...
│
└ Done! Your bot is ready.
Next steps:
cd my-bot
cp .env.example .env # add DISCORD_TOKEN + CLIENT_ID
npm run deploy # register slash commands
npm run dev # start in watch mode
my-bot/
├── .github/
│ └── workflows/
│ └── ci.yml ← Node 24 LTS CI
├── .discgen.json ← generator metadata for future upgrades
├── src/
│ ├── commands/
│ │ ├── moderation/ ← ban, kick, timeout, warn (Components v2)
│ │ ├── utility/ ← ping, help, userinfo, serverinfo, avatar, locale*
│ │ ├── fun/ ← coinflip, 8ball, meme (Components v2)
│ │ ├── economy/ ← balance, daily, leaderboard (db-aware, Components v2)
│ │ ├── music/ ← play, stop (placeholder)
│ │ └── prefix/ ← prefix commands (if commandType includes prefix)
│ ├── events/
│ │ ├── ready.ts
│ │ ├── interactionCreate.ts ← routes slash, buttons, selects, modals
│ │ └── messageCreate.ts ← routes prefix commands (if applicable)
│ ├── handlers/
│ │ ├── commandHandler.ts ← auto-loads slash + prefix commands
│ │ ├── interactionLoader.ts ← auto-loads all component handlers
│ │ └── eventHandler.ts ← auto-loads all events
│ ├── interactions/ ← "Components" feature
│ │ ├── buttons/
│ │ │ ├── example-button.ts
│ │ │ └── open-modal.ts
│ │ ├── selects/
│ │ │ └── example-select.ts
│ │ └── modals/
│ │ └── example-modal.ts
│ ├── i18n/ ← "i18n" feature (*)
│ │ ├── en.ts ← master locale, exports Locale interface
│ │ ├── de.ts ← German translation, typed against Locale
│ │ └── index.ts ← useT(), setGuildLocale(), supportedLocales
│ ├── database/
│ │ └── index.ts ← SQLite or PostgreSQL setup (if selected)
│ ├── services/ ← generated with: discgen-cli g service <name>
│ ├── types/
│ │ └── index.ts ← Command, PrefixCommand, Event, ButtonHandler, …
│ ├── utils/
│ │ ├── logger.ts ← zero-dep ANSI logger (debug / info / warn / error)
│ │ ├── env.ts ← typed env validator — exits on missing vars
│ │ ├── cooldown.ts ← per-user cooldown with auto-cleanup
│ │ ├── embed.ts ← Embed.success / .error / .info / .warn / .default
│ │ └── paginator.ts ← paginate() — Components v2 ⏮◀ X/Y ▶⏭ navigator
│ ├── deploy-commands.ts
│ └── index.ts
├── .env.example
├── .gitignore
├── .prettierrc
├── eslint.config.mjs
├── tsconfig.json
├── package.json
└── README.md
*— only present when the corresponding feature is selected
| Prompt | Choices |
|---|---|
| Command type | Slash · Prefix · Both |
| Features | Moderation · Utility · Fun · Economy · Components · i18n · Music |
| Database | None · SQLite · PostgreSQL |
| Package manager | npm · pnpm · bun · yarn (auto-detected from lockfile) |
| Git init | Yes · No |
| Install deps | Yes · No |
Skip the wizard entirely:
| Preset | Command type | Features | Database |
|---|---|---|---|
basic |
Slash | — | None |
moderation |
Slash | Moderation, Utility | None |
full |
Both | Moderation, Utility, Fun, Economy, Components, i18n | SQLite |
When you select the Components feature, your bot is scaffolded with a complete interaction routing system:
interactionCreate.ts
├── isChatInputCommand() → client.commands (slash commands)
├── isButton() → client.buttons (button clicks)
├── isAnySelectMenu() → client.selects (select menus)
└── isModalSubmit() → client.modals (modal forms)
Handlers are auto-loaded from src/interactions/ on startup — drop a file in, it just works. A full /demo command is included that showcases a Components v2 layout with a button, select menu, and a "Open Form" button that triggers a modal.
When you select the i18n feature, your bot gets a fully typed multi-language system — no JSON files, no external libraries.
| File | Purpose |
|---|---|
src/i18n/en.ts |
Master locale — exports the Locale interface and English strings |
src/i18n/de.ts |
German translation — typed against Locale, TypeScript enforces completeness |
src/i18n/index.ts |
useT(), setGuildLocale(), getLocale(), supportedLocales |
src/commands/utility/locale.ts |
/locale slash command (requires ManageGuild permission) |
// In any command:
const t = useT(interaction.guildId);
await interaction.reply(t.ping.pinging);
await interaction.reply(t.moderation.banned(target.tag, reason));
await interaction.reply(t.economy.dailyCooldown('2h 15m'));// src/i18n/fr.ts
import type { Locale } from './en.js';
const fr: Locale = {
errors: { commandFailed: 'Une erreur est survenue.', /* ... */ },
// TypeScript will error if any key is missing or has the wrong shape
};
export default fr;Then register it in src/i18n/index.ts:
import fr from './fr.js';
const locales: Record<string, Locale> = { en, de, fr };setGuildLocale() stores the choice in memory. To persist across restarts, save it in your database on /locale and restore it on startup:
// On startup — restore saved locales from DB
for (const row of db.prepare('SELECT guild_id, locale FROM settings').all()) {
setGuildLocale(row.guild_id, row.locale);
}import { Embed } from './utils/embed.js';
await interaction.reply({
embeds: [
Embed.success({ title: 'Done!', description: 'Action completed.', timestamp: true }),
Embed.error({ description: 'Something went wrong.' }),
Embed.info({ title: 'Info', fields: [{ name: 'Key', value: 'Value' }] }),
],
});Five presets with consistent colors: success · error · info · warn · default
import { paginate } from './utils/paginator.js';
await paginate({
interaction,
pages: [
{ heading: 'Page 1', body: 'First page content...' },
{ heading: 'Page 2', body: 'Second page content...' },
{ heading: 'Page 3', body: 'Third page content...' },
],
});Renders a fully navigable Components v2 layout with ⏮ ◀ 1 / 3 ▶ ⏭ buttons. Only the user who ran the command can navigate. Buttons auto-disable after 60 seconds of inactivity.
discgen-cli [name] [flags]
| Flag | Description |
|---|---|
--template <preset> |
Skip wizard: basic | moderation | full |
--output <dir> |
Scaffold into an explicit output directory |
--no-install |
Skip dependency installation |
--no-git |
Skip git initialization |
--dry-run |
Preview generated files without writing |
--version |
Print version |
--help |
Show help |
nameis a positional argument, not a flag:discgen-cli my-bot, not--name my-bot
discgen-cli list
discgen-cli generate <type> [name] [flags]
discgen-cli g <type> [name] [flags]
Add individual files to an existing bot project — like nest generate for NestJS.
discgen-cli g command greet # slash → src/commands/utility/greet.ts
discgen-cli g command ban --category moderation # custom subfolder
discgen-cli g command greet --prefix # prefix → src/commands/prefix/greet.tsdiscgen-cli g event guildMemberAdd # → src/events/guildMemberAdd.ts
discgen-cli g event # interactive: pick from 15 known Discord eventsdiscgen-cli g button confirm # → src/interactions/buttons/confirm.ts
discgen-cli g select role-picker # → src/interactions/selects/role-picker.ts
discgen-cli g modal feedback # → src/interactions/modals/feedback.tsdiscgen-cli g service avatar-api # → src/services/avatar-api.ts (singleton class)
discgen-cli g guard permissions # → src/guards/permissions.ts| Full | Aliases |
|---|---|
command |
cmd, c |
event |
evt, e |
button |
btn, b |
select |
sel, s |
modal |
m |
guard |
gd |
service |
svc |
# All equivalent
discgen-cli g command greet
discgen-cli g cmd greet
discgen-cli g c greet
# Dry-run: preview path without writing
discgen-cli g button confirm --dry-runcd my-bot
cp .env.example .envFill in your credentials from the Discord Developer Portal:
DISCORD_TOKEN=your_bot_token_here
CLIENT_ID=your_application_id_here
GUILD_ID=your_server_id_herenpm run deploy # register slash commands with Discord
npm run dev # start bot in watch mode (tsx watch)All scripts in the generated bot
| Script | Description |
|---|---|
npm run dev |
Start in watch mode (tsx watch) |
npm run build |
Compile TypeScript → dist/ |
npm start |
Run compiled bot from dist/ |
npm run deploy |
Register slash commands with Discord |
npm run lint |
Run ESLint |
npm run format |
Format with Prettier |
| Prompts | @clack/prompts |
| CLI parsing | commander |
| File I/O | native node:fs/promises |
| PM detection | native lockfile sniffing (no dependencies) |
| Layer | Technology |
|---|---|
| Language | TypeScript (strict mode) |
| Discord | discord.js v14 + Components v2 |
| Runtime | Node.js >= 24 |
| Build | tsup (ESM) |
| Lint | ESLint 10 flat config + @typescript-eslint v8 |
| Format | Prettier 3 |
| Database | better-sqlite3 · pg + drizzle-orm |
| CI | GitHub Actions (Node 24 LTS) |
Pull requests are welcome! See TODO.md for open tasks and CHANGELOG.md for what's changed.
git clone https://github.com/XSaitoKungX/discgen-cli
cd discgen-cli
npm install
npm run dev # run CLI locally with tsx
npm test # 184 unit tests
npm run build # compile to dist/
npm run lint # ESLint- Fork the repo
- Create a feature branch:
git checkout -b feat/your-feature - Commit with conventional commits:
feat: add xyz - Open a Pull Request
MIT © xsaitox