CIBER CODER ⚡

Aprovecha hasta 60% OFF y hasta 12 cuotas sin interés en CURSOS y CARRERAS

|

Hasta el 06/11 ⏰

CIBER CODER ⚡

Aprovecha hasta 60% OFF y hasta 12 cuotas sin interés en CURSOS y CARRERAS

|

Hasta el 06/11 ⏰

Hasta el 06/11 ⏰

CIBER CODER ⚡

Aprovecha hasta 60% OFF y hasta 12 cuotas sin interés en CURSOS y CARRERAS

Docker Compose paso a paso: cómo levantar tu app con base de datos en un solo comando

Guía gratuita de empleabilidad

2026
Descargar la guía

Guía gratuita: IA en tu equipo

2026
Descargar la guía

Dan Patiño

AI Strategy & Innovation en Coderhouse

Programación y Desarrollo Web

Docker Compose paso a paso: cómo levantar tu app con base de datos en un solo comando

Docker Compose paso a paso: cómo levantar tu app con base de datos en un solo comando

Publicado el

Resumen ejecutivo

  • Docker Compose te permite definir en un solo archivo YAML todos los servicios de tu proyecto (por ejemplo, tu app y una base de datos PostgreSQL) y levantarlos con un comando.

  • Resuelve lo que un Dockerfile solo no cubre: redes entre contenedores, variables de entorno, volúmenes para no perder datos y el orden de arranque.

  • En esta guía armás un ejemplo mínimo con un backend en Node.js (o Python) y Postgres, y aprendés a ver logs, reiniciar y apagar todo sin dejar basura.

  • Incluye los errores más frecuentes (puertos ocupados, «localhost» dentro del contenedor, la base que todavía no arrancó) y cómo sumarlo al README de tu portfolio.

Ya escribiste tu primer Dockerfile y lograste correr tu app en un contenedor. Pero tu backend necesita una base de datos, y empezás a encadenar comandos: crear una red, levantar Postgres con sus variables, montar un volumen, levantar la app apuntando a la base. Cada vez que alguien clona el repo tiene que repetir todo. Ahí entra Docker Compose.

Por qué ahora: los avisos de backend y DevOps junior piden cada vez más saber trabajar con contenedores, y que un proyecto de portfolio se levante con un solo comando es una de las mejores señales que podés dar a quien lo revisa. Si todavía no tenés clara la diferencia entre contenedores y orquestación, empezá por qué son Docker y Kubernetes y volvé a este tutorial.

Qué problema resuelve Docker Compose

Un Dockerfile describe cómo construir una imagen. Docker Compose describe cómo correr varios contenedores juntos. Según la documentación oficial de Docker, Compose es la herramienta para definir y ejecutar aplicaciones de varios contenedores: con un archivo de configuración creás e iniciás todos los servicios con un solo comando.

En la práctica, Compose se encarga de:

  • Crear una red donde los servicios se encuentran por nombre.

  • Pasar variables de entorno a cada servicio.

  • Montar volúmenes para que los datos sobrevivan cuando apagás los contenedores.

  • Definir dependencias y el orden de arranque.

Requisitos

  • Docker Desktop (Windows o Mac) o Docker Engine con el plugin de Compose (Linux).

  • Comprobá la instalación con docker compose version. Fijate que el comando actual es docker compose (con espacio); el viejo docker-compose con guion es la versión anterior.

  • Un backend simple con su Dockerfile. Si no tenés uno, cualquier API de práctica sirve.

Paso 1: la estructura del proyecto

mi-api/
├── compose.yaml
├── Dockerfile
├── .env
├── package.json
└── src/
    └── index.js
mi-api/
├── compose.yaml
├── Dockerfile
├── .env
├── package.json
└── src/
    └── index.js
mi-api/
├── compose.yaml
├── Dockerfile
├── .env
├── package.json
└── src/
    └── index.js
mi-api/
├── compose.yaml
├── Dockerfile
├── .env
├── package.json
└── src/
    └── index.js

Un Dockerfile mínimo para Node.js:

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]

Paso 2: el archivo compose.yaml

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
      interval: 5s
      timeout: 3s
      retries: 10

  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
    depends_on:
      db:
        condition: service_healthy

volumes:
  db-data:
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
      interval: 5s
      timeout: 3s
      retries: 10

  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
    depends_on:
      db:
        condition: service_healthy

volumes:
  db-data:
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
      interval: 5s
      timeout: 3s
      retries: 10

  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
    depends_on:
      db:
        condition: service_healthy

volumes:
  db-data:
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
      interval: 5s
      timeout: 3s
      retries: 10

  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
    depends_on:
      db:
        condition: service_healthy

volumes:
  db-data:

Y el archivo .env (que no se sube al repo):

DB_USER=app
DB_PASSWORD=cambiar-esta-clave
DB_NAME=tareas
DB_USER=app
DB_PASSWORD=cambiar-esta-clave
DB_NAME=tareas
DB_USER=app
DB_PASSWORD=cambiar-esta-clave
DB_NAME=tareas
DB_USER=app
DB_PASSWORD=cambiar-esta-clave
DB_NAME=tareas

Qué hace cada parte:

  • services: cada bloque es un contenedor. db usa la imagen oficial de PostgreSQL; api se construye desde tu Dockerfile.

  • environment: las variables se toman del archivo .env, así no dejás claves escritas en el YAML.

  • volumes: db-data es un volumen con nombre que guarda los datos de Postgres fuera del contenedor.

  • healthcheck + depends_on: la API espera a que la base responda de verdad, no solo a que el contenedor haya arrancado.

  • db:5432 en DATABASE_URL: dentro de la red de Compose, el nombre del servicio funciona como nombre de host.

Un detalle: en archivos viejos vas a ver una línea version: al principio. La especificación actual de Compose la considera obsoleta, así que podés omitirla.

Paso 3: levantar, mirar y apagar

# Construir y levantar todo en segundo plano
docker compose up -d --build

# Ver el estado de los servicios
docker compose ps

# Seguir los logs de la API
docker compose logs -f api

# Entrar a la base para probar una consulta
docker compose exec db psql -U app -d tareas

# Apagar y borrar contenedores y red (los datos quedan en el volumen)
docker compose down

# Apagar y borrar también el volumen (empezás de cero)
docker compose down -v
# Construir y levantar todo en segundo plano
docker compose up -d --build

# Ver el estado de los servicios
docker compose ps

# Seguir los logs de la API
docker compose logs -f api

# Entrar a la base para probar una consulta
docker compose exec db psql -U app -d tareas

# Apagar y borrar contenedores y red (los datos quedan en el volumen)
docker compose down

# Apagar y borrar también el volumen (empezás de cero)
docker compose down -v
# Construir y levantar todo en segundo plano
docker compose up -d --build

# Ver el estado de los servicios
docker compose ps

# Seguir los logs de la API
docker compose logs -f api

# Entrar a la base para probar una consulta
docker compose exec db psql -U app -d tareas

# Apagar y borrar contenedores y red (los datos quedan en el volumen)
docker compose down

# Apagar y borrar también el volumen (empezás de cero)
docker compose down -v
# Construir y levantar todo en segundo plano
docker compose up -d --build

# Ver el estado de los servicios
docker compose ps

# Seguir los logs de la API
docker compose logs -f api

# Entrar a la base para probar una consulta
docker compose exec db psql -U app -d tareas

# Apagar y borrar contenedores y red (los datos quedan en el volumen)
docker compose down

# Apagar y borrar también el volumen (empezás de cero)
docker compose down -v

Con down no dejás contenedores huérfanos ni redes sueltas. Usá down -v solo cuando quieras borrar los datos de la base.

Si tu backend es en Python

El compose.yaml es casi igual: cambia el Dockerfile (por ejemplo, partir de una imagen de Python, instalar dependencias con pip install -r requirements.txt y correr tu app con FastAPI o Flask) y el puerto expuesto. La parte de la base de datos, el volumen y el healthcheck no cambia. Para MySQL, reemplazás la imagen y las variables por las de la imagen oficial de MySQL.

Errores frecuentes y cómo resolverlos

  • «port is already allocated»: otro proceso usa ese puerto en tu máquina. Cambiá el lado izquierdo del mapeo, por ejemplo "3001:3000", o apagá el proceso que lo ocupa.

  • La API no conecta usando localhost: dentro de un contenedor, localhost es el propio contenedor. Usá el nombre del servicio (db).

  • La API arranca antes que la base y falla: agregá el healthcheck y condition: service_healthy, y sumá reintentos de conexión en tu código.

  • Cambiaste el código y no se refleja: reconstruí con docker compose up -d --build o configurá un volumen de código para desarrollo.

  • Cambiaste las variables de la base y no toma la nueva clave: Postgres solo usa esas variables al inicializar un volumen vacío. Si ya tenías datos, tenés que borrar el volumen con down -v (perdés los datos de prueba).

Cómo sumarlo a tu portfolio

En el README del proyecto, agregá una sección «Cómo correrlo» con tres pasos: clonar el repo, copiar .env.example a .env y ejecutar docker compose up -d --build. Que alguien pueda probar tu API completa con base de datos en dos minutos es una gran carta de presentación. Si querés dar el paso siguiente, aprendé a desplegar una app con Docker y GitHub Actions, y mirá qué hace un DevOps Engineer para entender hacia dónde puede crecer este conocimiento.

Curso recomendado de Coderhouse

Si querés dominar contenedores e infraestructura, el Curso de Devops & Cloud te enseña a containerizar con Docker, gestionar infraestructura con Terraform y orquestar con Kubernetes. Si tu foco es construir el backend que vas a containerizar, la Carrera de Desarrollo Backend te forma en Node.js y bases de datos SQL y NoSQL.

Preguntas frecuentes

¿Cuál es la diferencia entre Dockerfile y Docker Compose? El Dockerfile define cómo se construye una imagen. Docker Compose define cómo se ejecutan juntos varios contenedores, con sus redes, variables y volúmenes.

¿Docker Compose sirve para producción? Puede usarse en despliegues simples de un solo servidor, pero para producción a escala se suelen usar orquestadores como Kubernetes o servicios administrados en la nube.

¿Se pierden los datos al hacer docker compose down? No, si usás un volumen con nombre. Los datos solo se borran con docker compose down -v o eliminando el volumen.

¿Tengo que escribir la línea version en el compose.yaml? No. La especificación actual de Compose la considera obsoleta y podés omitirla.

Sobre el autor

Dan Patiño

Soy Dan Patiño, responsable de AI Strategy & Innovation en Coderhouse. Mi día a día consiste en fusionar la gestión táctica del e-commerce (CRO, Email Marketing y SEO) con el desarrollo de soluciones disruptivas. Me especializo en crear apps internas con IA para automatizar tareas y potenciar la innovación dentro del equipo. Creo fielmente que la tecnología es el mejor aliado de la estrategia. Para profundizar en mi recorrido profesional, te espero en mi perfil de LinkedIn.

Imagen promocionando quiz gratis de Coderhouse para encontrar tu formación.
Imagen promocionando quiz gratis de Coderhouse para encontrar tu formación.
Imagen promocionando quiz gratis de Coderhouse para encontrar tu formación.
Imagen promocionando quiz gratis de Coderhouse para encontrar tu formación.
Imagen promocionando quiz gratis de Coderhouse para encontrar tu formación.
Imagen promocionando quiz gratis de Coderhouse para encontrar tu formación.

NEWSLETTER

Suscríbete y mantente al día con las últimas noticias, ofertas exclusivas y recursos útiles directamente en tu correo.

Uruguay

© 2026 Coderhouse. Todos los derechos reservados.

NEWSLETTER

Suscríbete y mantente al día con las últimas noticias, ofertas exclusivas y recursos útiles directamente en tu correo.

Uruguay

© 2026 Coderhouse. Todos los derechos reservados.

NEWSLETTER

Suscríbete y mantente al día con las últimas noticias, ofertas exclusivas y recursos útiles directamente en tu correo.

Uruguay

© 2026 Coderhouse. Todos los derechos reservados.

NEWSLETTER

Suscríbete y mantente al día con las últimas noticias, ofertas exclusivas y recursos útiles directamente en tu correo.

Uruguay

© 2026 Coderhouse. Todos los derechos reservados.