Objetivos de aprendizaje
Después de leer este artículo podrás:
- Conocer los criterios que definen la base de datos adecuada para un proyecto Python
- Comparar SQLite, PostgreSQL, MySQL, MongoDB y Redis con las bibliotecas actuales
- Elegir la base por escenario: Django, FastAPI, bot, script o caché
Python se lleva bien con casi cualquier base de datos. Hay drivers maduros para PostgreSQL, MySQL, MongoDB y Redis, y SQLite ya viene en la biblioteca estándar. Eso es bueno, pero convierte la elección en una lista larga de opciones que parecen equivalentes.
En la práctica, la decisión depende de pocas preguntas: qué forma tienen tus datos, qué framework usas, cuántos procesos escriben a la vez y si tu código es síncrono o asíncrono. A continuación verás los criterios, cada opción con su biblioteca actual y una recomendación por escenario.
¿Qué criterios importan al elegir?#
- Forma de los datos. Usuarios, pedidos y pagos relacionados entre sí piden tablas, claves foráneas y
JOIN, es decir, una base relacional. Los documentos cuyos campos varían mucho de un registro a otro encajan mejor en una base de documentos. La diferencia entre los dos modelos está en SQL o NoSQL. - Framework. Django tiene su propio ORM y admite oficialmente cinco bases relacionales. FastAPI y Flask no imponen nada, y lo más común es usar SQLAlchemy.
- Concurrencia. Un script o un bot de un solo proceso es distinto de una API con varios workers escribiendo al mismo tiempo.
- Sync o async. Si tu código usa
asyncio(FastAPI, bots), prefiere un driver con API asíncrona para no bloquear el bucle de eventos. - Operación. Un archivo SQLite no necesita servidor. Los demás necesitan host, credenciales, conexiones y copias de los datos.
¿Cuándo basta SQLite?#
El módulo sqlite3 forma parte de la biblioteca estándar de Python. SQLite guarda todo en un archivo y corre dentro de tu proceso, sin servidor aparte. Es ideal para scripts, herramientas de línea de comandos, prototipos, pruebas y apps pequeñas de un solo proceso.
import sqlite3
from contextlib import closing
with closing(sqlite3.connect("app.db")) as con:
con.execute("PRAGMA journal_mode=WAL")
con.execute(
"CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, text TEXT NOT NULL)"
)
with con: # commit al final del bloque, rollback si hay error
con.execute("INSERT INTO notes (text) VALUES (?)", ("hola",))
for row in con.execute("SELECT id, text FROM notes"):
print(row)Un detalle que confunde a mucha gente: usar la conexión en un bloque with hace commit o rollback, pero no cierra la conexión. Por eso el ejemplo usa contextlib.closing, como sugiere la propia documentación.
El límite está en la escritura. La documentación de SQLite explica que admite un escritor a la vez por archivo de base de datos y que no es adecuado cuando muchas máquinas acceden a la misma base por la red. Si el archivo vive en una carpeta que el deploy reemplaza, los datos se van con ella.
¿Por qué PostgreSQL es la opción por defecto?#
PostgreSQL es una base relacional cliente-servidor pensada para muchas conexiones simultáneas, con transacciones, índices variados, JSONB y extensiones. Para casi cualquier proyecto Python que vaya a crecer, es la opción de la que menos te arrepentirás. Más detalles en qué es PostgreSQL.
Las bibliotecas más usadas:
- psycopg 3 (el paquete
psycopg): el driver actual, con APIs síncrona y asíncrona. La documentación de Django lo recomienda y advierte que el soporte de psycopg2 probablemente se retire en el futuro. - asyncpg: driver solo asíncrono, común en proyectos con FastAPI.
- SQLAlchemy 2: ORM y toolkit SQL muy usado fuera de Django. Funciona con PostgreSQL, MySQL y MariaDB, SQLite, Oracle y SQL Server, y en PostgreSQL acepta psycopg, psycopg2, asyncpg y pg8000.
Con SQLAlchemy, el mismo código corre en SQLite en tu computadora y en PostgreSQL en producción. Solo cambia la URL: sin DATABASE_URL, el ejemplo usa sqlite:///app.db; en producción, define algo como postgresql+psycopg://usuario:clave@host/base.
import os
from sqlalchemy import String, create_engine, select
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(80))
engine = create_engine(os.environ.get("DATABASE_URL", "sqlite:///app.db"))
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(User(name="Ana"))
session.commit()
for user in session.scalars(select(User).where(User.name == "Ana")):
print(user.id, user.name)Crea el engine una sola vez, al iniciar el proceso. Mantiene un pool de conexiones; crear uno por petición es la receta del error too many connections. Para producción, instala el driver con pip install "psycopg[binary]" sqlalchemy. Las diferencias entre SQLite y PostgreSQL siguen apareciendo en tipos y funciones, así que prueba con la misma base que usarás en producción antes de publicar.
¿Y MySQL o MariaDB?#
MySQL y MariaDB son bases relacionales tan capaces como PostgreSQL para la mayoría de las aplicaciones web. Django admite las dos y recomienda el driver mysqlclient. Otras opciones son PyMySQL, escrito en Python puro, y MySQL Connector/Python, de Oracle. En SQLAlchemy, la URL queda mysql+mysqldb:// o mysql+pymysql://.
Elige MySQL cuando tu equipo ya lo conoce, cuando vas a integrarte con un sistema que ya lo usa o cuando es lo que ofrece tu hosting. La comparación detallada está en PostgreSQL o MySQL.
¿Cuándo tiene sentido MongoDB en Python?#
MongoDB guarda documentos parecidos a diccionarios de Python, sin esquema fijo. Encaja en catálogos con atributos variables, registros de eventos y perfiles que cambian con cada versión de la app. Mira qué es MongoDB.
El driver oficial es PyMongo. Cuidado con los tutoriales viejos: MongoDB dejó Motor obsoleto el 14 de mayo de 2025 en favor de la API asíncrona del propio PyMongo (AsyncMongoClient). Motor recibió solo correcciones de errores hasta el 14 de mayo de 2026 y, después, solo correcciones críticas hasta el fin de su soporte.
import os
from pymongo import MongoClient
client = MongoClient(os.environ["MONGODB_URI"])
profiles = client["app"]["profiles"]
profiles.update_one(
{"_id": "user-42"},
{"$inc": {"xp": 10}, "$setOnInsert": {"plan": "basic"}},
upsert=True,
)
print(profiles.find_one({"_id": "user-42"}))En Django, MongoDB no tiene soporte oficial. Existe el backend de terceros django-mongodb-backend, y la documentación de Django advierte que las funciones que admiten los backends de terceros varían bastante. Si el proyecto es Django, quédate en lo relacional.
¿Redis sirve como base de datos principal?#
Redis guarda los datos en memoria y responde muy rápido. En Python, el paquete redis trae cliente síncrono y asíncrono (redis.asyncio). Es la herramienta adecuada para caché, sesiones, rate limit, colas de tareas (Celery y RQ pueden usar Redis como broker) y contadores.
Como base principal exige cuidado: la escritura en disco es configurable, y los datos tienen que caber en la RAM. En la mayoría de los proyectos, Redis va junto a PostgreSQL o MongoDB, no en su lugar. La diferencia está explicada en Redis como caché o como base de datos.
¿Qué base elegir en cada escenario?#
| Escenario | Recomendación | Biblioteca |
|---|---|---|
| Script, CLI, prototipo, pruebas | SQLite | sqlite3 (estándar) |
| Proyecto Django | PostgreSQL | ORM de Django + psycopg 3 |
| API con FastAPI o Flask | PostgreSQL | SQLAlchemy 2 + psycopg 3 o asyncpg |
| Sistema heredado o equipo que ya usa MySQL | MySQL o MariaDB | mysqlclient o PyMySQL |
| Documentos de forma variable | MongoDB | PyMongo (sync o AsyncMongoClient) |
| Caché, sesiones, colas | Redis, junto a la base principal | redis (redis.asyncio para async) |
| Bot pequeño de Discord o Telegram | SQLite, después PostgreSQL | sqlite3, después psycopg 3 |
Si tienes dudas, empieza con PostgreSQL y SQLAlchemy (o el ORM de Django). Ganas una base que aguanta el crecimiento y una capa que oculta buena parte de las diferencias entre motores. Para bots, el análisis detallado está en qué base de datos usar en un bot de Discord.
¿Qué errores evitar?#
- Armar SQL con f-strings. Usa siempre parámetros (
?en sqlite3,%sen psycopg, o el ORM). Una f-string con entrada del usuario abre la puerta a la inyección SQL. - Abrir una conexión por petición. Crea el engine o el pool una vez y reutilízalo.
- Un driver síncrono dentro de código async. Una consulta bloqueante detiene todo el bucle de eventos de FastAPI o del bot.
- Credenciales en el código. Lee la URL de conexión de una variable de entorno, como en los ejemplos.
- Ninguna copia de los datos. Programa volcados (
pg_dump,mongodump) y prueba la restauración antes de necesitarla.
Para publicar la aplicación junto con la base, mira cómo alojar FastAPI, Flask o Django.
Cómo hacerlo en Square Cloud#
En Square Cloud puedes alojar MongoDB, PostgreSQL, MySQL y Redis desde el plan Standard (R$44,99 al mes); Hobby no incluye bases de datos. Creas la base en el panel (nombre, memoria y motor), y se aprovisiona en segundos en el mismo datacenter que tus aplicaciones, con una latencia media de alrededor de 1 ms. PostgreSQL es el nativo, sin extensiones, y Redis tiene persistencia.
Del lado de Python casi no cambia nada: pon la URL de conexión completa que te entrega el panel en una variable de entorno de la aplicación (DATABASE_URL, MONGODB_URI) y léela con os.environ, como en los ejemplos. El cambio se aplica en el siguiente reinicio, sin rebuild. TLS es obligatorio: descarga el certificado en el panel y apunta el driver a la CA; en PostgreSQL y MongoDB el cliente también presenta el certificado .pem. En Redis, usa rediss://. Como la base de datos acepta conexiones externas, puedes ejecutar el mismo código en tu máquina con el mismo certificado.
Puedes tomar snapshots manuales cuando quieras, y todo plan que incluye bases de datos tiene también un snapshot automático diario, guardado durante 7 días. Un snapshot se puede restaurar en la misma base de datos, en otra del mismo motor o en una nueva, o descargar como .zip. Mira los motores y planes en la página de hosting de bases de datos.
Hosting de bases de datos
MongoDB, PostgreSQL, MySQL y Redis junto a tu app
Preguntas frecuentes
¿Cuál es la mejor base de datos para Django?
PostgreSQL. Django admite oficialmente PostgreSQL, MariaDB, MySQL, Oracle y SQLite, y muchas de las funciones extra del framework, como los campos de array y la búsqueda de texto completo, existen solo para PostgreSQL. Para empezar, el SQLite por defecto del proyecto funciona.
¿Python necesita instalar algo para usar SQLite?
Normalmente no. El módulo sqlite3 forma parte de la biblioteca estándar de Python, y SQLite corre dentro de tu proceso, sin servidor aparte. Algunas distribuciones compilan Python sin él, así que comprueba que el import funcione.
¿Todavía debo usar Motor para MongoDB con asyncio?
No en un proyecto nuevo. MongoDB dejó Motor obsoleto en mayo de 2025 en favor de la API asíncrona del propio PyMongo, que trae la clase AsyncMongoClient. Motor dejó de recibir correcciones normales en mayo de 2026.
¿psycopg2 o psycopg 3?
psycopg 3 (el paquete psycopg) para proyectos nuevos. Admite async, y la documentación de Django lo recomienda y advierte que el soporte de psycopg2 probablemente se retire en el futuro.
Más en Bases de datos
Ver los 24 artículos- ¿Cuánto cuesta una base de datos en la nube?Una base de datos en la nube cuesta desde cero hasta cientos de dólares al mes. Qué define el precio: instancia, disco, tráfico, snapshots y cómo estimar el tuyo.
- Cómo hospedar una base de datos en la nubePara hospedar una base de datos, elige el motor, crea la instancia, guarda la cadena de conexión en una variable de entorno y prueba la conexión. Guía paso a paso.
- Qué es Redis y para qué sirveRedis es una base de datos en memoria que guarda pares clave-valor y estructuras de datos. Mira cómo funciona, para qué sirve y cuándo no usarlo.
- Cómo hacer un respaldo de tu base de datosRespalda MySQL, PostgreSQL y MongoDB con mysqldump, pg_dump y mongodump, y restaura el dump. Mira los comandos, cómo verificar y los errores comunes.