spearkit

Introduction

discord.js++ — a developer-experience-first layer over discord.js. spearkit re-exports all of discord.js (so it's a drop-in replacement) and adds an ergonomic, fully type-safe API…

Contents

  1. Getting started — install, first bot, project layout.
  2. ClientSpearClient, intents, register, start, deployment.
  3. Commands — slash commands, subcommands, permissions, deployment.
  4. Options — typed option builders, choices, autocomplete.
  5. Components — buttons, selects, modals, custom-id routing.
  6. Context menus — user and message "Apps" commands.
  7. Events — the event() helper and the event registry.
  8. Contexts — reply helpers shared by every handler.
  9. Guards — role/permission/owner/guild preconditions.
  10. Auto-defer — beat the 3-second Unknown interaction error.
  11. Permissions & hierarchy — moderation preflight checks.
  12. Discord API errors — recognise and recover from DiscordAPIError.
  13. Cooldowns — per-user/role/guild rate limiting.
  14. Scheduled tasks — cron and interval jobs.
  15. Prefix commands — classic !text commands.
  16. Collectors — await messages, modals and component clicks.
  17. Key-value store & settings — persist per-guild config + dynamic prefix.
  18. Messages & limits — split long output, truncate text.
  19. Logging — structured, leveled, scoped logging.
  20. Usage tracking — record who used what (store + Discord channel).
  21. Environment & dotenv — load .env and read typed env vars.
  22. Graceful shutdown — close cleanly on SIGINT/SIGTERM.
  23. Plugins — bundling features into reusable units.
  24. File-based loading — one file per command/event/component.
  25. Migrating from discord.js — the drop-in path.
  26. API reference — every exported symbol.

Why spearkit

  • Drop-in. import { Client, EmbedBuilder } from "spearkit" — every discord.js export is available, so you can migrate one file at a time.
  • Fully type-safe. No any or unknown leaks into your handlers. Option values, custom-id params and modal fields are all inferred from your definitions.
  • Co-located. A command's options and handler, a button's appearance and click logic, a modal's fields and submit logic — each lives in one place.
  • No boilerplate. No interactionCreate switch statements; spearkit routes commands, autocomplete, buttons, selects and modals for you.

Thirty-second tour

import { SpearClient, Intents, command, option, button, row, event } from "spearkit";

const client = new SpearClient({ intents: Intents.default });

const greet = command({
  name: "greet",
  description: "Greet someone",
  options: { who: option.user({ description: "Who", required: true }) },
  run: (ctx) => ctx.reply(`Hello ${ctx.options.who}!`), // who: User
});

const ping = button({
  id: "ping:{n}",
  label: "Ping",
  run: (ctx) => ctx.update(`pong #${ctx.params.n}`), // n: string
});

client.register(greet, ping, event("clientReady", (c) => console.log(c.user.tag)));
await client.start(process.env.DISCORD_TOKEN);
await client.deployCommands({ guildId: process.env.GUILD_ID });

On this page