Objetivos de aprendizado
Depois de ler este artigo, você vai conseguir:
- Escolher entre SQLite, PostgreSQL, MongoDB e Redis para o seu bot
- Ver o código de conexão de cada opção em Node.js
- Evitar os erros que fazem um bot perder dados
Nesta página
Quase todo bot acaba precisando guardar algo: o prefixo de cada servidor, o saldo de uma economia, as advertências de moderação, o canal de boas-vindas. O que fica numa variável some no próximo restart, então você precisa de um banco de dados.
A lista parece longa, mas na prática são quatro candidatos: SQLite, PostgreSQL, MongoDB e Redis. O que decide entre eles é o jeito como o seu bot grava e relaciona os dados.
Quais critérios importam na hora de escolher?#
Quatro perguntas resolvem quase todos os casos:
- Quantos processos gravam no banco? Um bot de um processo só é diferente de um bot com shards em processos separados, ou de um bot e um painel web que gravam juntos.
- Seus dados têm relações? Usuários com itens, itens com trocas, trocas com histórico: isso pede tabelas e
JOIN. Configurações soltas por servidor não pedem. - O que acontece com os dados num deploy? Se o banco é um arquivo dentro da pasta do bot, um deploy que substitui a pasta pode levar o arquivo junto. Um banco em servidor separado não tem esse risco.
- Quanta operação você aceita? Um arquivo não precisa de servidor. Um banco cliente-servidor precisa de host, credenciais e conexão.
Quando SQLite é a melhor escolha?#
SQLite é um banco em um único arquivo, sem servidor. Em Node.js, a biblioteca better-sqlite3 é síncrona e simples. Os exemplos deste artigo usam ES modules ("type": "module" no package.json) e uma versão recente do Node.js, como pede a versão atual do better-sqlite3:
import Database from 'better-sqlite3';
const db = new Database('bot.db');
db.pragma('journal_mode = WAL');
db.exec(`
CREATE TABLE IF NOT EXISTS guild_settings (
guild_id TEXT PRIMARY KEY,
prefix TEXT NOT NULL DEFAULT '!'
)
`);
const setPrefix = db.prepare(`
INSERT INTO guild_settings (guild_id, prefix) VALUES (?, ?)
ON CONFLICT(guild_id) DO UPDATE SET prefix = excluded.prefix
`);
const getPrefix = db.prepare('SELECT prefix FROM guild_settings WHERE guild_id = ?');
setPrefix.run('123456789012345678', '?');
console.log(getPrefix.get('123456789012345678')?.prefix); // "?"Prós: zero configuração, rápido, ótimo para começar, não depende de rede.
Contras: a documentação do SQLite diz que ele aceita apenas um escritor por vez por arquivo de banco, e que não é indicado quando muitos computadores acessam o mesmo banco pela rede. Se o arquivo mora em um disco que some ou é substituído a cada deploy, você perde os dados.
Use quando: é um único processo, os dados cabem em um arquivo e você sabe onde esse arquivo fica guardado de forma durável.
Quando PostgreSQL é a melhor escolha?#
PostgreSQL é um banco relacional cliente-servidor. Ele foi feito para muitas conexões e escritas simultâneas (com controle de concorrência MVCC), tem transações e permite consultas com relações. É a escolha mais segura para economia, ranking, tickets e qualquer coisa em que perder ou duplicar um registro dói. Veja mais em o que é PostgreSQL.
Com a biblioteca pg, use um Pool e crie só um para o bot inteiro:
import pg from 'pg';
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
// sem este listener, um erro em uma conexão ociosa derruba o processo
pool.on('error', (err) => console.error('erro no pool do PostgreSQL', err));
await pool.query(`
CREATE TABLE IF NOT EXISTS balances (
user_id TEXT PRIMARY KEY,
coins BIGINT NOT NULL DEFAULT 0
)
`);
// $1, $2: parâmetros evitam SQL injection
await pool.query(
`INSERT INTO balances (user_id, coins) VALUES ($1, $2)
ON CONFLICT (user_id) DO UPDATE SET coins = balances.coins + excluded.coins`,
['123456789012345678', 50],
);
const { rows } = await pool.query('SELECT coins FROM balances WHERE user_id = $1', ['123456789012345678']);
console.log(rows[0].coins);Prós: transações, integridade, escala com vários processos, o dado fica fora da pasta do bot.
Contras: exige um servidor de banco e uma string de conexão. Para um bot de cinco comandos, é mais do que o necessário.
Quando MongoDB faz sentido?#
MongoDB guarda documentos parecidos com JSON, sem esquema fixo. É cômodo quando cada registro tem campos diferentes ou o formato muda a cada versão do bot, como um perfil de jogador com itens variados. Mais detalhes em o que é MongoDB e quando usar.
import { MongoClient } from 'mongodb';
const client = new MongoClient(process.env.MONGODB_URI);
await client.connect();
const profiles = client.db('bot').collection('profiles');
await profiles.updateOne(
{ _id: '123456789012345678' },
{ $inc: { xp: 10 }, $setOnInsert: { createdAt: new Date() } },
{ upsert: true },
);
console.log(await profiles.findOne({ _id: '123456789012345678' }));Prós: modelagem flexível, upsert e $inc atômicos.
Contras: sem esquema, é fácil gravar campos inconsistentes, e as relações entre coleções ficam por sua conta. Se você usa o cluster gratuito do MongoDB Atlas, saiba que ele tem limite de armazenamento (índices contam) e pausa clusters que ficam muito tempo sem conexão. Confira os valores atuais na documentação de limites do Atlas.
Redis serve como banco do bot?#
Redis guarda os dados em memória (a gravação em disco é opcional e configurável) e é muito rápido. Ele é ótimo para cooldowns, contadores, filas e cache, mas dados que não podem se perder devem ficar em um banco principal. Entenda a diferença em Redis como cache ou como banco. Antes de adicionar Redis, pergunte se uma Map em memória já resolve: para um processo só, geralmente resolve.
Qual banco escolher em cada cenário?#
| Cenário | Recomendação |
|---|---|
| Bot pequeno, um processo, configurações por servidor | SQLite |
| Economia, ranking, tickets, transações | PostgreSQL |
| Perfis com campos variáveis, protótipo rápido | MongoDB |
| Bot com shards em processos separados | PostgreSQL ou MongoDB |
| Bot e painel web gravando nos mesmos dados | PostgreSQL ou MongoDB |
| Cooldowns e contadores temporários | Map em memória ou Redis |
| Dados de teste | JSON ou SQLite |
Na dúvida, comece com SQLite se o bot é pequeno e você sabe onde o arquivo fica guardado, ou com PostgreSQL se já sabe que o bot vai crescer. Trocar depois é possível, mas dá trabalho de migração.
Quais erros fazem um bot perder dados?#
- Banco dentro da pasta que o deploy substitui. Confirme que o arquivo sobrevive a um novo envio, ou use um banco externo.
- Uma conexão nova a cada comando. Crie o cliente ou o
Pooluma vez, ao iniciar, e reutilize. - Concatenar texto em SQL. Use sempre parâmetros (
?,$1). - Credenciais no código. Coloque a string de conexão em variável de ambiente, como no caso do token do bot.
- Nenhuma cópia dos dados. Teste restaurar uma cópia antes de precisar dela.
Quanto o banco pesa na conta mensal do bot aparece em quanto custa hospedar um bot.
Como fazer isso na Square Cloud#
Depois de escolher o banco, falta decidir onde ele roda. Na Square Cloud, o Hobby (a partir de R$ 12,49 por mês) hospeda o bot, mas não inclui hospedagem de banco. A hospedagem de MongoDB, PostgreSQL, MySQL e Redis começa no plano Standard.
Você cria o banco no painel (nome, memória e motor), no mesmo datacenter das aplicações, com latência média de cerca de 1 ms. O painel entrega a URL de conexão completa e o certificado para baixar. O TLS é obrigatório, então o cliente precisa confiar na CA baixada (no PostgreSQL e no MongoDB ele também apresenta o certificado .pem). Coloque a URL na variável de ambiente do bot (DATABASE_URL ou MONGODB_URI, como nos exemplos acima).
Cada banco é um nó único, com até 512 conexões. O mínimo é de 512 MB para Redis e 1024 MB para os outros motores. Você tira snapshots manuais quando quiser, e todo plano com bancos inclui também um snapshot automático diário. Um snapshot restaura no mesmo banco ou num banco novo.
Se o seu bot é pequeno, SQLite no Hobby continua sendo uma opção válida: o disco da aplicação persiste entre restarts e deploys, e um novo commit sobrescreve só os arquivos que estão no ZIP, então deixe o arquivo do banco fora dele. Veja a hospedagem de bots do Discord e os planos.
Hospedagem de bots
Seu bot online 24/7, com reinício automático
Perguntas frequentes
Posso guardar os dados do bot em um arquivo JSON?
Para testes, sim. Em produção não: duas escritas ao mesmo tempo ou uma queda no meio da gravação podem corromper o arquivo, e você reescreve tudo a cada alteração. SQLite resolve isso com a mesma simplicidade.
SQLite aguenta um bot grande?
Aguenta bastante leitura, mas só permite um escritor por vez por arquivo. Para um único processo isso raramente é problema. Com shards em processos separados ou vários processos gravando, prefira um banco cliente-servidor.
MongoDB ou PostgreSQL para bot do Discord?
Os dois funcionam. PostgreSQL é melhor quando os dados têm relações (usuários, itens, transações). MongoDB é cômodo quando cada documento tem formato diferente ou muda com frequência.
Preciso de Redis no meu bot?
Só se você precisa de cache ou contadores muito rápidos, como cooldowns e filas. Redis não substitui o banco principal. Para a maioria dos bots, uma Map em memória ou o próprio banco bastam.
Mais em Bots
Ver todos os 33 artigos- Quanto custa hospedar um bot do Discord?O custo de hospedar um bot do Discord depende de RAM, tempo online, banco de dados e serviços externos. Veja como estimar o seu e onde o gasto aparece.
- Rodar bot no celular (Termux) ou no PC vs hospedar: o que mudaUm bot no PC ou no celular (Termux) fica offline quando o aparelho desliga, dorme ou perde a rede. Compare as três opções e veja quando cada uma serve.
- Como deixar um bot do Discord online 24/7Para deixar um bot do Discord online 24/7, rode o processo numa máquina sempre ligada com reinício automático. Veja PC, VPS com pm2 ou systemd e hospedagem.
- Por que meu bot do Discord fica offline (e como resolver)Bot do Discord offline quase sempre é processo caído, token inválido, intent não habilitada ou falta de memória. Veja como diagnosticar cada causa e corrigir.