NUEVO 📢 Oferta de lanzamiento limitada: ¡hasta un 70% de descuento en tu primer mes, en todos los juegos!Ver planes

Cómo usar Prisma con MySQL en un bot de Discord

Hosting de bots de DiscordUpdated Nov 6, 202610 min read

Respuesta corta. Usa Prisma 7 con el adaptador de driver @prisma/adapter-mariadb, que Prisma documenta para MySQL y MariaDB. En PlayNHost, prisma migrate dev no puede ejecutarse contra la base de datos de tu bot, porque necesita crear una base de datos temporal "shadow" y los usuarios de base de datos aquí no pueden crear bases de datos. Escribe la primera migración con prisma migrate diff, que no necesita ninguna base de datos, y deja que un script postinstall ejecute prisma generate y prisma migrate deploy en el servidor. Todos los planes de bot incluyen una base de datos MySQL. Probamos el código y los comandos de abajo el 6 de noviembre de 2026 con Prisma 7.10.1, discord.js 14 y Node.js 22, contra MariaDB 10.11 con una cuenta de base de datos configurada como la nuestra (sin permiso para crear bases de datos, 20 conexiones, límite de consulta de 120 segundos), pero no con un inicio de sesión real en Discord.

Prisma 7, no la versión más reciente de npm

El 6 de noviembre de 2026 la etiqueta latest del paquete prisma en npm apunta a un release candidate de Prisma 8 (8.0.0-rc.30), y el quickstart de MySQL del propio Prisma es el de Prisma 7: instala prisma@prev y @prisma/client@7. Por eso esta guía fija todos los paquetes de Prisma en ^7. Un simple npm install prisma te daría la versión 8.

Lo que necesitas

  • Un bot de discord.js escrito en TypeScript. Nuestro tipo Node.js Bot ejecuta con tsx un archivo principal que termina en .ts, así que no hace falta compilar nada antes: Cómo ejecutar un bot de Discord en TypeScript.
  • Un plan de bot de PlayNHost con el tipo Node.js Bot. Todos los planes incluyen una base de datos.
  • Node.js y npm en tu propio ordenador, para escribir la migración una vez.

1. Crea la base de datos y las variables

  1. Abre el servidor de tu bot en el panel, haz clic en Bases de datos, luego en Base de datos nueva y en Crear base de datos.
  2. Se abre la página de la nueva base de datos (más adelante, haz clic en ella en Tus bases de datos). Déjala abierta y, en Config lista para usar, elige Generic URL en Config para: es la cadena de conexión mysql://... que necesita la línea de comandos de Prisma.
  3. Abre la página Bot, el panel Entorno, haz clic en Pegar un archivo .env y pega seis líneas con tus valores. Para DATABASE_URL, pega la Generic URL exactamente como se muestra: las contraseñas de nuestras bases de datos pueden contener caracteres como @ y +, que Prisma necesita codificados con porcentaje dentro de una URL, y la Generic URL ya viene codificada.
    DB_HOST=your-host
    DB_PORT=3306
    DB_NAME=your-database
    DB_USER=your-username
    DB_PASSWORD=your-password
    DATABASE_URL=mysql://your-username:your-password@your-host:3306/your-database
  4. DB_PASSWORD y DATABASE_URL reciben una insignia Secreto: se guardan como solo escritura. Haz clic en Importar 6 variables.

El bot en sí se conecta con los cinco valores DB_, que se pasan al adaptador uno por uno como en el quickstart de Prisma. DATABASE_URL solo sirve para los comandos prisma que se ejecutan durante la instalación.

2. Los archivos del proyecto

package.json

{
  "name": "my-discord-bot",
  "private": true,
  "type": "module",
  "scripts": {
    "postinstall": "prisma generate && prisma migrate deploy"
  },
  "dependencies": {
    "@prisma/adapter-mariadb": "^7",
    "@prisma/client": "^7",
    "discord.js": "^14"
  },
  "devDependencies": {
    "prisma": "^7"
  }
}

prisma7.config.ts (Prisma 7.10 y posteriores usan este nombre, para que no choque con el prisma.config.ts de Prisma 8)

import { defineConfig } from "prisma/config";

export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: process.env.DATABASE_URL,
  },
});

prisma/schema.prisma

generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mysql"
}

model Warning {
  id        Int      @id @default(autoincrement())
  guildId   String   @db.VarChar(20)
  userId    String   @db.VarChar(20)
  reason    String   @db.VarChar(200)
  createdAt DateTime @default(now())

  @@index([guildId, userId])
}

index.ts

import { Client, Events, GatewayIntentBits, InteractionContextType, MessageFlags, REST, Routes, SlashCommandBuilder } from "discord.js";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
import { PrismaClient } from "./generated/prisma/client";

// One client for the whole bot. The values come from the Environment pane.
const adapter = new PrismaMariaDb({
  host: process.env.DB_HOST,
  port: Number(process.env.DB_PORT),
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  connectionLimit: 5,
});
const prisma = new PrismaClient({ adapter });

const commands = [
  new SlashCommandBuilder()
    .setName("warn")
    .setDescription("Warn a member and count their warnings")
    .setContexts(InteractionContextType.Guild)
    .addUserOption((o) => o.setName("user").setDescription("Who to warn").setRequired(true))
    .addStringOption((o) => o.setName("reason").setDescription("Why").setRequired(true).setMaxLength(200))
    .toJSON(),
];

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.once(Events.ClientReady, async (c) => {
  await new REST().setToken(process.env.DISCORD_TOKEN!).put(Routes.applicationCommands(c.user.id), { body: commands });
  console.log(`Logged in as ${c.user.tag}`);
});

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isChatInputCommand() || interaction.commandName !== "warn" || !interaction.guildId) return;
  const user = interaction.options.getUser("user", true);
  const reason = interaction.options.getString("reason", true);
  try {
    await prisma.warning.create({ data: { guildId: interaction.guildId, userId: user.id, reason } });
    const total = await prisma.warning.count({ where: { guildId: interaction.guildId, userId: user.id } });
    await interaction.reply(`${user} has ${total} warning(s).`);
  } catch (err) {
    console.error(err);
    if (!interaction.replied) await interaction.reply({ content: "Could not save the warning. Try again later.", flags: MessageFlags.Ephemeral }).catch(console.error);
  }
});

client.login(process.env.DISCORD_TOKEN);

setContexts(InteractionContextType.Guild) y la comprobación !interaction.guildId mantienen /warn fuera de los mensajes directos. El try/catch es importante: sin él, discord.js pasa una consulta fallida a su evento error, y cuando nadie escucha ahí, Node.js detiene el bot.

3. Escribe la primera migración en tu ordenador

En la carpeta del proyecto, en tu propio ordenador (en Windows, crea a mano las carpetas prisma\migrations\0_init en lugar de usar mkdir -p):

npm install --ignore-scripts
mkdir -p prisma/migrations/0_init
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql

migrate diff compara una base de datos vacía con tu esquema y escribe el SQL, sin conectarse a ninguna base de datos. --ignore-scripts omite el postinstall, que intentaría llegar a una base de datos. El archivo empieza con -- CreateTable y CREATE TABLE `Warning`.

4. Sube los archivos e inicia

  1. En Archivos, sube package.json, prisma7.config.ts, index.ts y la carpeta prisma con schema.prisma y migrations. No subas node_modules ni generated: el servidor genera ambas.
  2. En la página Bot, panel Código, pon Archivo de entrada en index.ts.
  3. Pulsa Iniciar y abre Consola. La instalación ejecuta tu postinstall: verás Generated Prisma Client (7.10.1), luego All migrations have been successfully applied., luego [PlayNHost] Starting your bot y Logged in as ....

La consola también muestra npm warn install-scripts 2 packages had install scripts blocked para prisma y @prisma/engines. La versión de npm de nuestra imagen de Node.js 22 bloquea los scripts de instalación de las dependencias salvo que estén permitidos. Tu propio postinstall se ejecuta igualmente, y en nuestra prueba Prisma generó, migró y consultó sin esos scripts.

¿Por qué no prisma migrate dev?

prisma migrate dev crea primero una base de datos shadow temporal para comprobar tus migraciones. El usuario de base de datos de tu bot puede trabajar dentro de su propia base de datos, pero no puede crear otras nuevas, así que en nuestros servidores se detiene con:

Prisma Migrate could not create the shadow database. Please make sure the database user has permission to create databases. Read more about the shadow database (and workarounds) at https://pris.ly/d/migrate-shadow

Original error: Error code: P1010

User was denied access on the database `prisma_migrate_shadow_db_...`

prisma migrate deploy solo aplica archivos de migración y no necesita base de datos shadow, por eso el postinstall lo usa. Tampoco puedes apuntar migrate dev a la base de datos del bot desde tu propio ordenador: la base de datos solo acepta conexiones desde servidores de PlayNHost y desde phpMyAdmin.

Cambiar el esquema más adelante

  1. En tu ordenador, ejecuta npx prisma migrate dev --name más un nombre para el cambio, contra un MySQL o MariaDB propio, por ejemplo uno en Docker: define DATABASE_URL en tu terminal con esa base de datos, porque prisma7.config.ts la lee del entorno. Escribe una carpeta nueva en prisma/migrations.
  2. Sube la carpeta de la nueva migración y el schema.prisma modificado.
  3. El servidor ejecuta npm install, y con él tu postinstall, solo cuando han cambiado package.json, package-lock.json o la versión de Node.js, cuando falta node_modules, o en el primer inicio pasado más de un día desde la última instalación. Para aplicar la migración ahora, cambia package.json (por ejemplo su version) o borra la carpeta node_modules en Archivos, y reinicia.

Memoria: la instalación es la parte pesada

Instalamos este proyecto desde cero en un contenedor limitado a 512 MB, como nuestro plan de bot más pequeño. La instalación, con prisma generate y prisma migrate deploy, tardó 41 segundos y llegó a un pico de 386 MB de memoria (sin contar la caché de archivos) en una ejecución y de 417 MB en una segunda, sin que se produjera ninguna muerte por falta de memoria en ninguna. Cabe en el plan de 512 MB con menos de 100 MB de margen, así que un proyecto más grande o más paquetes podrían pasarse. La misma instalación sin Prisma (solo discord.js y mysql2) llegó a un pico de 147 MB.

Límites y errores

  • 20 conexiones a la vez por usuario de base de datos, entre todos los procesos que usan el mismo acceso. Mantén connectionLimit bajo; 5 es más que suficiente para un bot.
  • Una consulta que dura más de 120 segundos se detiene, con el error 1969 Query execution was interrupted (max_statement_time exceeded).
  • 500 MB por base de datos: al llegar a 500 MB, las escrituras se detienen hasta que borres filas. Las copias de seguridad del servidor no incluyen la base de datos. Expórtala de vez en cuando desde phpMyAdmin.
  • Los problemas de conexión tienen las mismas causas que con mysql2 (contraseña incorrecta, host o puerto incorrectos, una variable que falta en Entorno, conectar desde tu propio ordenador), pero los mensajes son distintos: el adaptador de MariaDB usa el driver mariadb, no mysql2, y no registramos sus mensajes. Las causas están en Cómo usar una base de datos MySQL con un bot de discord.js.

¿Prefieres SQL plano con mysql2 o aiomysql? discord.js (mysql2), discord.py (aiomysql). La visión general: Cómo usar una base de datos con tu bot de Discord. ¿Necesitas un servidor de bot con base de datos incluida? Mira los planes de bot.

¿Ya tienes tu bot en otro proveedor? Tráelo con nosotros

NUESTROS ÚLTIMOS BLOGS