Un bot de Discord puede moderar un servidor, automatizar el soporte, publicar alertas o conectar una comunidad con una API. Pero un bot moderno ya no es un simple script que lee los mensajes que empiezan por !. Hoy, la base sólida consiste en usar comandos slash, pedir el mínimo de intents y permisos, mantener el token fuera del código y separar el registro de los comandos del arranque del bot.
Este tutorial construye un proyecto Node.js real con:
/ping, para comprobar la disponibilidad y la latencia;/servidor, para mostrar información sobre el servidor;/decir, reservado a los miembros autorizados a gestionar mensajes;- un token almacenado fuera del código;
- una protección contra las menciones inyectadas mediante
/decir; - respuestas de error limpias y un apagado controlado del proceso;
- un despliegue de prueba por servidor y después un despliegue global en producción.
El código sigue discord.js 14.27.0, publicada en julio de 2026, y Node.js 24 LTS. Node.js recomienda las ramas Active LTS o Maintenance LTS para producción, y la rama 20 ya no recibe versiones nuevas. Consulta siempre las versiones de Node.js mantenidas y las versiones publicadas de discord.js antes de una instalación nueva.
Qué es realmente un bot de Discord
Una aplicación de Discord puede usar dos vías complementarias:
- el Gateway, una conexión WebSocket persistente que transmite los eventos en tiempo real, por ejemplo una interacción o la llegada de un miembro;
- la API HTTP, utilizada para registrar un comando, enviar un mensaje o modificar un recurso.
discord.js ofrece una abstracción en JavaScript sobre estas API. El Client mantiene la conexión al Gateway; el objeto REST realiza las llamadas HTTP. La introducción oficial a los bots de Discord describe esta arquitectura.
Una precisión importante: automatiza únicamente una cuenta de bot creada en el Developer Portal. Discord prohíbe los «self-bots», es decir, la automatización de una cuenta de usuario normal, e indica que esa práctica puede provocar el cierre de la cuenta. Consulta la política oficial sobre self-bots.
Requisitos previos
Necesitas una cuenta de Discord, un servidor de Discord de pruebas donde puedas gestionar aplicaciones, Node.js 24 LTS, un editor como Visual Studio Code, una terminal y nociones de JavaScript: variables, funciones y async/await.
Comprueba tu entorno:
node --version
npm --version
discord.js 14.27.0 declara oficialmente Node.js 18 o superior como requisito. Aun así elegimos Node.js 24 LTS en esta guía, por una razón sencilla: la rama 20 ya no recibe versiones nuevas, y hacer funcionar un bot expuesto a Internet sobre una rama que ya no recibe parches de seguridad no es razonable. Cualquier versión 24 reciente sirve.
1. Crear la aplicación en el Discord Developer Portal
Abre el Discord Developer Portal y después:
- haz clic en New Application;
- ponle un nombre a la aplicación;
- acepta las condiciones y confirma;
- en General Information, copia el Application ID;
- en Bot, personaliza el nombre y el avatar si hace falta;
- en Bot, usa Reset Token para generar el token y cópialo una sola vez.
Discord crea hoy un usuario bot con cada nueva aplicación. El recorrido oficial se detalla en Building your first Discord Bot.
El token no es un identificador público
El token permite conectarse como el bot. Quien lo obtenga puede usar sus permisos en todos los servidores donde esté instalado.
No pongas nunca ese token en index.js, en una captura de pantalla, en un ticket o un mensaje de Discord, en Git aunque el repositorio sea privado, ni en un ejemplo publicado en un blog.
Si se filtra, vuelve de inmediato a Bot > Reset Token y sustituye el valor en el alojamiento. Borrar un commit antiguo no basta: el secreto debe revocarse.
2. Configurar la instalación y los permisos
En la página Installation del Developer Portal:
- activa Guild Install;
- usa preferiblemente el Discord Provided Link;
- añade los scopes
applications.commandsybot; - concede solo View Channels y Send Messages para este proyecto;
- abre el enlace, selecciona tu servidor de pruebas y autoriza la aplicación.
No concedas Administrator «para que funcione»: ese permiso salta las restricciones de canales y da mucho más poder del necesario.
El permiso para usar /decir se controlará a nivel de comando mediante ManageMessages. El bot, por su parte, solo necesita ver el canal y enviar allí un mensaje. Esta distinción aplica el principio de mínimo privilegio.
Permisos de Discord y jerarquía de roles
Los permisos del bot no siempre bastan. Para gestionar un rol, expulsar a un miembro o cambiar un apodo, el rol más alto del bot debe además situarse por encima del objetivo en la jerarquía. Discord detalla este mecanismo en su referencia oficial de permisos.
3. Entender los intents antes de programar
Los Gateway Intents determinan qué categorías de eventos envía Discord al bot. Reducen los datos recibidos y el acceso a información sensible.
Este tutorial solo usa GatewayIntentBits.Guilds. Ese intent no privilegiado basta para recibir las interacciones de los comandos slash instalados en los servidores. No necesitamos leer todos los mensajes ni descargar la lista completa de miembros.
Tres intents son privilegiados: GuildPresences, GuildMembers y MessageContent. Deben activarse en el Developer Portal y declararse en el código. Discord puede cerrar la conexión con el código 4014 cuando un bot solicita un intent privilegiado no autorizado.
Desde el 10 de junio de 2026, la revisión de los intents privilegiados ya no se basa en el número de servidores sino en el número de usuarios únicos que pueden ver tu aplicación, en todos los servidores. Por encima de 10 000, hace falta solicitar acceso. Un bot presente en cincuenta servidores grandes puede por tanto alcanzar ese umbral. Las reglas actualizadas están en la documentación del Gateway y en la guía de revisión de intents privilegiados.
Para un bot nuevo, los comandos slash suelen evitar MessageContent. Discord los recomienda como alternativa a los antiguos comandos de texto con prefijo.
4. Inicializar el proyecto Node.js
Crea la carpeta del proyecto:
mkdir mi-bot-discord
cd mi-bot-discord
npm init -y
npm install [email protected]
mkdir src
Fijamos aquí la versión de discord.js para obtener una instalación reproducible. Conserva el archivo package-lock.json: en el servidor, npm ci podrá instalar exactamente las versiones validadas.
La estructura final será la siguiente:
mi-bot-discord/
├── src/
│ ├── commands.js
│ ├── deploy-commands.js
│ └── index.js
├── .env
├── .env.example
├── .gitignore
├── package-lock.json
└── package.json
package.json
Sustituye su contenido por:
{
"name": "mi-bot-discord",
"version": "1.0.0",
"private": true,
"type": "module",
"engines": {
"node": ">=24.0.0"
},
"scripts": {
"deploy:guild": "node --env-file=.env src/deploy-commands.js",
"deploy:global": "node --env-file=.env src/deploy-commands.js --global",
"start": "node --env-file=.env src/index.js"
},
"dependencies": {
"discord.js": "14.27.0"
}
}
El campo engines es aquí una elección nuestra, no una exigencia de discord.js: documenta la rama de Node sobre la que debe ejecutarse el proyecto y hace fallar la instalación en una versión más antigua.
"type": "module" activa la sintaxis moderna import. Node.js sabe cargar .env de forma nativa con --env-file, lo que evita una dependencia adicional. La sintaxis y el orden de prioridad de las variables están documentados en la referencia de la línea de comandos de Node.js.
.gitignore
node_modules/
.env
npm-debug.log*
.env.example
Este archivo describe las variables necesarias sin contener ningún secreto:
DISCORD_TOKEN=
DISCORD_CLIENT_ID=
DISCORD_GUILD_ID=
.env
Crea después tu copia local:
DISCORD_TOKEN=pega_aqui_el_token_del_bot
DISCORD_CLIENT_ID=pega_aqui_el_application_id
DISCORD_GUILD_ID=pega_aqui_el_id_del_servidor_de_pruebas
Para copiar el identificador del servidor, activa Ajustes de usuario > Avanzado > Modo desarrollador, luego haz clic derecho sobre el icono del servidor y elige Copiar ID del servidor.
No publiques nunca el .env real. Ejecuta git status antes del primer commit: el archivo .env no debe aparecer entre los archivos rastreados.
5. Definir los comandos slash
Crea src/commands.js:
import {
PermissionFlagsBits,
SlashCommandBuilder,
} from 'discord.js';
export const commands = [
new SlashCommandBuilder()
.setName('ping')
.setDescription('Mide la latencia del bot'),
new SlashCommandBuilder()
.setName('servidor')
.setDescription('Muestra la información del servidor'),
new SlashCommandBuilder()
.setName('decir')
.setDescription('Publica un mensaje a través del bot')
.addStringOption((option) =>
option
.setName('texto')
.setDescription('Mensaje a publicar')
.setRequired(true)
.setMaxLength(1000),
)
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages),
];
export const commandsJSON = commands.map((command) => command.toJSON());
SlashCommandBuilder fabrica un objeto JSON compatible con la API. La restricción de /decir no es por tanto un simple control visual en nuestro código: Discord también define ManageMessages como permiso por defecto del comando. Consulta las reglas de los application commands.
6. Registrar los comandos en Discord
El código del bot y la lista de comandos son dos recursos distintos. Modificar commands.js no actualiza automáticamente la interfaz de Discord: hay que enviar la nueva definición a la API.
Crea src/deploy-commands.js:
import { REST, Routes } from 'discord.js';
import { commandsJSON } from './commands.js';
const token = process.env.DISCORD_TOKEN;
const clientId = process.env.DISCORD_CLIENT_ID;
const guildId = process.env.DISCORD_GUILD_ID;
const deployGlobally = process.argv.includes('--global');
if (!token || !clientId || (!deployGlobally && !guildId)) {
throw new Error(
'Variables requeridas: DISCORD_TOKEN, DISCORD_CLIENT_ID' +
(deployGlobally ? '' : ' y DISCORD_GUILD_ID'),
);
}
const rest = new REST({ version: '10' }).setToken(token);
const route = deployGlobally
? Routes.applicationCommands(clientId)
: Routes.applicationGuildCommands(clientId, guildId);
try {
console.log(
`Registrando ${commandsJSON.length} comando(s) ` +
(deployGlobally ? 'globales' : `en el servidor ${guildId}`),
);
const result = await rest.put(route, { body: commandsJSON });
console.log(`${result.length} comando(s) registrado(s).`);
} catch (error) {
console.error('Fallo en el registro de los comandos:', error);
process.exitCode = 1;
}
Durante el desarrollo, registra los comandos únicamente en tu servidor de pruebas:
npm run deploy:guild
La petición PUT sustituye todos los comandos de esa ruta. No pongas este despliegue en index.js: reescribir los comandos en cada reinicio es inútil y mezcla dos operaciones distintas.
Cuando el bot esté validado y listo para instalarse en varios servidores:
npm run deploy:global
Tras cualquier cambio de nombre, descripción, opción o permiso, vuelve a ejecutar el comando de despliegue correspondiente.
7. Programar el cliente y tratar las interacciones
Crea src/index.js:
import {
Client,
Events,
GatewayIntentBits,
MessageFlags,
} from 'discord.js';
const token = process.env.DISCORD_TOKEN;
if (!token) {
throw new Error('Falta la variable DISCORD_TOKEN.');
}
const client = new Client({
intents: [GatewayIntentBits.Guilds],
});
client.once(Events.ClientReady, (readyClient) => {
console.log(
`Conectado como ${readyClient.user.tag} ` +
`en ${readyClient.guilds.cache.size} servidor(es).`,
);
});
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
try {
switch (interaction.commandName) {
case 'ping': {
const gatewayLatency = Math.round(client.ws.ping);
const interactionLatency = Date.now() - interaction.createdTimestamp;
await interaction.reply({
content:
`¡Pong! Gateway: ${gatewayLatency} ms · ` +
`interacción: ${interactionLatency} ms`,
flags: MessageFlags.Ephemeral,
});
break;
}
case 'servidor': {
if (!interaction.inGuild()) {
await interaction.reply({
content: 'Este comando solo funciona dentro de un servidor.',
flags: MessageFlags.Ephemeral,
});
break;
}
await interaction.reply({
content:
`Servidor: **${interaction.guild.name}**\n` +
`Miembros: **${interaction.guild.memberCount}**\n` +
`Identificador: \`${interaction.guild.id}\``,
flags: MessageFlags.Ephemeral,
});
break;
}
case 'decir': {
if (!interaction.inGuild() || !interaction.channel?.isTextBased()) {
await interaction.reply({
content: 'No hay ningún canal de texto utilizable.',
flags: MessageFlags.Ephemeral,
});
break;
}
const text = interaction.options.getString('texto', true);
await interaction.channel.send({
content: text,
allowedMentions: { parse: [] },
});
await interaction.reply({
content: 'Mensaje publicado.',
flags: MessageFlags.Ephemeral,
});
break;
}
default:
await interaction.reply({
content: 'Comando desconocido.',
flags: MessageFlags.Ephemeral,
});
}
} catch (error) {
console.error(
`Error durante /${interaction.commandName} ` +
`(interacción ${interaction.id}):`,
error,
);
const response = {
content: 'Se ha producido un error interno. Inténtalo más tarde.',
flags: MessageFlags.Ephemeral,
};
if (interaction.replied || interaction.deferred) {
await interaction.followUp(response).catch(console.error);
} else {
await interaction.reply(response).catch(console.error);
}
}
});
client.on(Events.Error, (error) => {
console.error('Error del cliente de Discord:', error);
});
async function shutdown(signal) {
console.log(`${signal} recibido: apagando el bot.`);
await client.destroy();
process.exit(0);
}
process.once('SIGINT', () => void shutdown('SIGINT'));
process.once('SIGTERM', () => void shutdown('SIGTERM'));
await client.login(token);
¿Por qué estas decisiones técnicas?
GatewayIntentBits.Guildses el único intent necesario para estos comandos.interaction.isChatInputCommand()ignora limpiamente los demás tipos de interacción.getString('texto', true)indica que la opción es obligatoria y devuelve una cadena.allowedMentions: { parse: [] }impide que un usuario inyecte una mención interpretada como@everyone, un rol o un usuario mediante/decir.MessageFlags.Ephemeralhace que las confirmaciones y los errores sean visibles solo para quien lanzó el comando.SIGINTySIGTERMpermiten a la terminal o al proveedor cerrar la conexión limpiamente.- el mensaje destinado al usuario sigue siendo genérico; los detalles del error se escriben en los registros sin exponer la traza técnica en Discord.
8. Respetar el límite de tres segundos de las interacciones
Discord invalida la interacción si el bot no envía una respuesta inicial en tres segundos. El token de interacción sigue siendo utilizable durante quince minutos para modificar la respuesta o enviar mensajes de seguimiento. Estos plazos se detallan en Receiving and Responding to Interactions.
Para una base de datos o una API que pueda tardar más de tres segundos, acusa recibo de inmediato:
await interaction.deferReply({
flags: MessageFlags.Ephemeral,
});
const result = await operacionLenta();
await interaction.editReply({
content: `Resultado: ${result}`,
});
No uses reply() después de deferReply(): termina con editReply() o followUp().
9. Lanzar y probar el bot en local
Registra primero los comandos y arranca después el proceso:
npm run deploy:guild
npm start
La consola debe mostrar un mensaje parecido a:
Conectado como MiBot#0000 en 1 servidor(es).
En Discord, prueba:
/ping: la respuesta es privada;/servidor: aparecen el nombre, el número de miembros y el identificador;/decir texto:Holacon una cuenta autorizada;/decircon una cuenta sinManageMessages: el comando debe estar no disponible por defecto;/decir texto:@everyone prueba: el texto puede aparecer, pero no debe dispararse ninguna mención.
Prueba en un servidor separado antes de producción. Comprueba también los permisos canal por canal: un rol puede permitir Send Messages de forma global y estar denegado en un canal concreto.
10. Añadir un mensaje de bienvenida, solo si hace falta
La llegada de un miembro no está cubierta por el intent Guilds. Para escuchar guildMemberAdd hay que activar Server Members Intent en Bot > Privileged Gateway Intents, añadir GatewayIntentBits.GuildMembers en el cliente, guardar el identificador del canal en WELCOME_CHANNEL_ID y comprobar que el bot puede ver el canal y escribir en él.
Modificación del cliente:
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
],
});
Añade después el evento:
client.on(Events.GuildMemberAdd, async (member) => {
const channelId = process.env.WELCOME_CHANNEL_ID;
if (!channelId) return;
const channel = await member.guild.channels
.fetch(channelId)
.catch(() => null);
if (!channel?.isTextBased()) return;
await channel.send({
content: `¡Bienvenido ${member} a **${member.guild.name}**!`,
allowedMentions: { users: [member.id] },
});
});
Un identificador de canal es más fiable que una búsqueda por nombre: varios canales pueden llamarse de forma parecida, y un cambio de nombre no rompe la configuración.
No actives MessageContent, GuildMembers o GuildPresences «por si acaso». Cada intent aumenta los datos recibidos y el alcance de una eventual vulneración.
11. Alojar el bot de forma continua en OuiPanel
Un bot lanzado en tu ordenador se detiene con la terminal, la suspensión o la conexión a Internet. Para un servicio continuo, usa un entorno Node.js supervisado.
La página alojamiento de bot de Discord de OuiHeberg anuncia Node.js, el reinicio automático, copias de seguridad, la planificación de tareas y el cambio de versión desde el panel. La documentación de OuiPanel dedicada a discord.js detalla la subida por gestor de archivos o SFTP, la elección del archivo de arranque y la instalación de las dependencias en el primer lanzamiento.
Preparar la subida
Sube src/, package.json, package-lock.json y, opcionalmente, .env.example sin ningún valor real.
No subas node_modules/, que se recreará para el sistema del servidor, ni la carpeta .git/, ni tu .env local si prefieres crearlo directamente en el panel.
Configuración recomendada
- selecciona Node.js 24 LTS;
- sube los archivos por el gestor o por SFTP;
- crea
.envdirectamente en el servidor con las tres variables; - define
src/index.jscomo archivo principal si el panel pide un «Main File»; - deja que la instalación npm se ejecute en el primer arranque;
- arranca el servidor y revisa los registros;
- activa una copia de seguridad tras validar la configuración.
El script start de este proyecto carga .env. Los comandos slash solo necesitan desplegarse tras una modificación de su esquema: ejecuta npm run deploy:guild durante las pruebas o npm run deploy:global para la publicación.
Para los precios y características actualizados, consulta la página de las ofertas Node.js.
12. Seguridad y explotación en producción
Reducir los privilegios
- no concedas nunca
Administratorpor defecto; - activa únicamente los intents que usa el código;
- limita los comandos sensibles con
setDefaultMemberPermissions(); - comprueba también los permisos del lado del servidor para las operaciones críticas;
- evita registrar tokens, cabeceras HTTP o datos personales innecesarios.
Gestionar las dependencias
Conserva package-lock.json e instala en producción con:
npm ci --omit=dev
Antes de una actualización:
npm outdated
npm audit
npm audit es una señal útil, no una garantía absoluta. Lee los cambios de versión, prueba en un servidor de Discord separado y despliega después. Una copia de seguridad no sustituye a un repositorio Git limpio.
Respetar los rate limits
Discord aplica límites por ruta y un límite HTTP global. Una respuesta 429 indica que hay que esperar la duración anunciada por Retry-After o retry_after. discord.js gestiona la cola de las llamadas habituales; no sortees ese mecanismo con bucles de peticiones paralelas. Discord indica un límite global de 50 peticiones HTTP por segundo y bot en su documentación de rate limits.
Registrar lo que realmente ayuda
Para cada error de comando, registra como mínimo la hora, el nombre del comando, el identificador de la interacción, el tipo de error y una traza técnica del lado del servidor.
Evita conservar el contenido de los mensajes si no es necesario. Define un plazo de retención de los registros y restringe su acceso.
Supervisar el proceso
Un bot «en línea» no está necesariamente operativo. Comprueba que el proceso se reinicia tras una caída controlada, que /ping responde, que la latencia no se desvía de forma duradera, que los errores y desconexiones son visibles en los registros y que las copias de seguridad pueden restaurarse realmente.
13. Resolución de problemas: errores frecuentes
| Síntoma o error | Causa probable | Corrección |
|---|---|---|
An invalid token was provided | token ausente, antiguo o mal copiado | revisa .env; si hace falta, restablece el token en el Developer Portal |
Used disallowed intents o cierre 4014 | intent privilegiado solicitado pero no activado o no autorizado | quita el intent innecesario o actívalo en Bot, y comprueba su elegibilidad |
Cannot find package 'discord.js' | dependencias no instaladas | ejecuta npm ci o reinicia la instalación desde el panel |
| Los comandos no aparecen | Application ID incorrecto, Guild ID incorrecto o comandos no desplegados | revisa .env y vuelve a ejecutar npm run deploy:guild |
Interaction failed | ninguna respuesta inicial en tres segundos | usa deferReply() y después editReply() |
Missing Permissions o código de API 50013 | falta un permiso del bot o del canal | revisa el rol, los permisos del canal y la jerarquía |
/decir no es visible para un miembro | el miembro no tiene ManageMessages | es el comportamiento esperado; ajusta el permiso del comando si hace falta |
| El bot está desconectado en el alojamiento | proceso detenido, versión de Node incorrecta o archivo principal incorrecto | elige Node.js 24 y src/index.js, y lee el primer error de los registros |
| Comandos antiguos todavía visibles | esquema no redesplegado en la ruta correcta | vuelve a lanzar el despliegue guild o global correspondiente |
| Las respuestas se envían dos veces | varios procesos usan el mismo token | detén las instancias duplicadas y mantén un proceso por bot, salvo una arquitectura de sharding deliberada |
Empieza siempre por el primer error de la consola. Los mensajes siguientes suelen ser consecuencias del mismo fallo inicial.
14. Hacer evolucionar el proyecto sin volverlo frágil
El enrutador switch es deliberadamente legible para tres comandos. Cuando el proyecto crezca:
- coloca cada comando en su propio módulo con
datayexecute; - carga los módulos al arrancar en una
Collection; - valida todas las entradas antes de una llamada a una API o a una base de datos;
- usa consultas parametrizadas para SQL;
- añade pruebas unitarias sobre la lógica de negocio;
- separa los entornos de desarrollo y de producción;
- prevé las migraciones de base de datos y su vuelta atrás;
- plantéate el sharding solo cuando el tamaño del bot lo justifique.
Una buena arquitectura no consiste en multiplicar carpetas el primer día. Consiste en aislar las responsabilidades cuando se vuelven difíciles de probar o de mantener.
Preguntas frecuentes
¿Se puede crear un bot de Discord gratis?
Sí. El Developer Portal, la API de Discord, Node.js y discord.js pueden usarse gratuitamente. Ejecutarlo en local no cuesta nada, pero depende de tu ordenador. Un alojamiento permanente resulta útil cuando el bot debe seguir disponible sin tu máquina.
¿Hay que saber programar?
Hay que entender las bases de JavaScript y del asincronismo para mantener un bot de forma fiable. Copiar un token en un ejemplo puede bastar para mostrar «en línea», pero no para asegurar, diagnosticar o hacer evolucionar el servicio.
¿Por qué usar comandos slash en lugar de un prefijo?
Son nativos en la interfaz de Discord, validan las opciones, muestran la ayuda automáticamente y evitan a menudo el intent privilegiado MessageContent. Además tienen permisos configurables por comando.
¿Por qué el bot está en línea pero no responde?
La conexión al Gateway puede funcionar mientras los comandos no se han registrado, el bot no tiene acceso al canal o el gestor de interacciones lanza un error. Consulta la consola, prueba /ping y comprueba después la ruta de despliegue y los permisos del canal.
¿Debo redesplegar los comandos en cada arranque?
No. Vuelve a desplegarlos únicamente cuando cambien su nombre, descripción, opciones o permisos. El proceso principal solo debe conectarse y tratar las interacciones.
¿Necesito el intent Message Content?
No para los comandos slash de esta guía. Solo resulta pertinente si una funcionalidad debe leer realmente el contenido de mensajes ordinarios y cumple las condiciones de Discord.
¿Qué alojamiento elegir para empezar?
Un entorno Node.js gestionado conviene a un primer bot: instalación de dependencias, versión de Node seleccionable, consola y reinicio están centralizados. Un VPS da más control, pero exige administrar el sistema, las actualizaciones, los servicios y la seguridad.
Conclusión
Ya dispones de un bot de Discord moderno: comandos slash registrados por separado, un solo intent no privilegiado, permisos mínimos, token fuera del código, errores gestionados y apagado limpio. Esta base es lo bastante sencilla para entenderse y lo bastante rigurosa para acoger una base de datos, una API externa, un sistema de tickets o funciones de moderación.
Antes de la puesta en producción, repite tres controles: el .env no está rastreado por Git, el bot no tiene ningún permiso innecesario y los comandos se han probado con una cuenta no administradora. Despliega después en un entorno Node.js supervisado y vigila realmente los registros.
Fuentes y documentación de referencia
- Discord: Building your first Discord Bot
- Discord: Bots and apps overview
- Discord: Application Commands
- Discord: Receiving and Responding to Interactions
- Discord: Gateway e intents
- Discord: Getting Started with Privileged Intent Review
- Discord: Permissions
- Discord: Rate Limits
- Discord Support: self-bots
- discord.js: documentación 14.27.0
- discord.js: versiones publicadas
- Node.js: calendario de versiones
- Node.js: opción --env-file
- OuiHeberg: alojamiento de bot de Discord
- OuiPanel: alojar un bot discord.js
