Skip to main content

Start with the mental shift

Chameleon is not trying to be discord.js with different method names. The biggest differences are architectural:
  • cached entities are plain objects, not active class instances
  • actions live on managers such as client.messages or client.guilds
  • many APIs return explicit result objects instead of throwing on normal HTTP failures
  • event typing is based on discriminated unions, not wide generic emitter overloads
  • the cache is flatter and less graph-shaped
If you treat Chameleon like a thin wrapper around raw Discord data plus typed helpers, the API starts to feel coherent very quickly.

Client bootstrapping

discord.js:
Chameleon:
The practical difference is that the token is part of the client constructor, and the client exposes managers directly after construction.

Entities are data, not behavior

discord.js often encourages this style:
In Chameleon, you usually work through managers:
That is intentional. A cached Message is a value object. The manager owns the action surface.

Cache access is flatter

Instead of traversing deep trees like:
Chameleon keeps a flatter store:
In practice, you often do not touch the store directly unless you are optimizing or building custom flows. The normal path is still the corresponding manager.

REST failures are values

One of the biggest flow changes is error handling. discord.js often pushes you toward try/catch around REST calls. Chameleon returns a result object:
That means:
  • expected API failures are explicit
  • branching is local and predictable
  • scripts and jobs can avoid exception-heavy control flow

Commands are definition-first

Instead of subclassing command structures or stitching builders together ad hoc, Chameleon leans on definition helpers:
For slash command options, ctx.options is inferred from the option builders you use. If you are coming from discord.js command builders, the nearest equivalent to setDefaultMemberPermissions(...) is:
That writes Discord default_member_permissions in the deployed command payload.

Components and modals are more typed than they look

Chameleon has two component styles:
  • classic message components through ActionRow
  • Components V2 layout through Container and Section
Modals now have a fluent builder with typed field inference:
That is a different style from discord.js, but it removes a lot of manual parsing.

Map of common translations

Migration strategy that usually works

If you have an existing bot, avoid a big-bang rewrite. Move in this order:
  1. Port client bootstrapping and intents.
  2. Port event handlers and replace entity-instance methods with managers.
  3. Replace command registration with command(...).
  4. Replace component and modal flows with the Chameleon builders.
  5. Only then revisit caching assumptions and optimize store access.
This keeps the migration about control flow first, not micro-DX details.

What tends to surprise people

  • You will write client.messages.send(...) more often than message.reply(...).
  • IDs matter more because relations are less object-graph-driven.
  • Some surfaces are already polished, especially typed modals and newer V2 builders.
  • Some lower-level APIs still feel closer to Discord than to a fully abstracted ORM-style framework.
That tradeoff is deliberate. Chameleon is optimizing for explicitness and memory shape, not maximal concealment of the Discord API.
Last modified on June 13, 2026