Skip to content

Repository files navigation

discgen-cli banner

discgen-cli icon

discgen-cli

Scaffold a production-ready Discord Bot in seconds — not hours.

npm version npm downloads Node.js TypeScript discord.js MIT License

Quick Start · Generated Output · Features · CLI Reference · generate · Contributing


✨ Why discgen-cli?

🎛️ 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

📦 Installation

# No install needed — always uses latest version
npx discgen-cli my-bot

# Or install globally
npm install -g discgen-cli
discgen-cli my-bot

Requires Node.js >= 24. Checked on startup — exits with a clear error if too old.


🚀 Quick Start

npx discgen-cli my-bot

The 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

🎬 Wizard Demo

┌  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

📁 What Gets Generated

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


🧩 Features

Wizard Options

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

--template Presets

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

🔘 Component Interactions

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.


🌐 i18n — TypeScript-native Localization

When you select the i18n feature, your bot gets a fully typed multi-language system — no JSON files, no external libraries.

What gets generated

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)

Usage

// 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'));

Adding a new language

// 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 };

Persisting guild locales

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);
}

🎨 Utility Helpers (always generated)

Embed — typed embed builder

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

paginate() — Components v2 page navigator

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.


🚩 CLI Reference

Create a new project

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

name is a positional argument, not a flag: discgen-cli my-bot, not --name my-bot

List available options

discgen-cli list

Generate files — generate / g

discgen-cli generate <type> [name] [flags]
discgen-cli g <type> [name] [flags]

generate Subcommand

Add individual files to an existing bot project — like nest generate for NestJS.

Commands

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.ts

Events

discgen-cli g event guildMemberAdd   # → src/events/guildMemberAdd.ts
discgen-cli g event                  # interactive: pick from 15 known Discord events

Component Interactions

discgen-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.ts

Services & Guards

discgen-cli g service avatar-api     # → src/services/avatar-api.ts  (singleton class)
discgen-cli g guard permissions      # → src/guards/permissions.ts

Type Aliases

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-run

▶️ After Scaffolding

cd my-bot
cp .env.example .env

Fill 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_here
npm 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

🛠️ Tech Stack

discgen-cli itself

Prompts @clack/prompts
CLI parsing commander
File I/O native node:fs/promises
PM detection native lockfile sniffing (no dependencies)

Generated bot

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)

🤝 Contributing

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
  1. Fork the repo
  2. Create a feature branch: git checkout -b feat/your-feature
  3. Commit with conventional commits: feat: add xyz
  4. Open a Pull Request

📄 License

MIT © xsaitox


Built with ❤️ for the Discord developer community

npm

Releases

Packages

Used by

Contributors

Languages