Supabase no te da copias de seguridad en el plan gratuito. He creado las mías, gratis y automáticas.

Candado sobre fondo mostaza, icono de copia de seguridad cifrada

Si usas el plan gratuito de Supabase, tu base de datos no tiene ninguna copia de seguridad. No es una opción que tengas desactivada: no existe. La documentación de Supabase lo dice: los backups automáticos diarios son solo para los planes de pago (Pro, Team, Enterprise). A los proyectos del plan gratuito lo único que les recomienda es que exporten los datos a mano, de vez en cuando, y los guarden en otro sitio.

Eso es mucho pedir para algo tan importante como una copia de seguridad: que te acuerdes tú, que la hagas a mano.

Así que he creado la mía: gratis, automática, y además cifrada (de eso hablamos más abajo). Y como me pareció una tontería quedármela para mí, aquí tienes la guía completa, paso a paso, con el código ya escrito, para que te crees la tuya en tu repositorio, en minutos.

A quién le sirve esto

Te importa si tienes un proyecto en el plan gratuito de Supabase, aunque sea pequeño o esté todavía en pruebas. No hace falta tener miles de usuarios para que perder la base de datos entera sea un problema real.

Qué vas a necesitar

  • Un proyecto en Supabase.
  • Un repositorio en GitHub (puede ser uno que ya tengas o uno nuevo).
  • Una terminal, para un único comando en el Paso 3.

Paso 1: repositorio privado

Crea (o usa) un repositorio de GitHub marcado como Private. Nunca público: va a contener copias de datos reales, aunque estén cifradas.

Paso 2: consigue la cadena de conexión de Supabase

  1. Entra en tu proyecto en Supabase.
  2. Ve a Connect (arriba del panel).
  3. Elige el modo Direct Connection String y luego Session Pooler y copia la cadena completa (postgresql://...).
Modal Connect to your project en Supabase con Direct Connection string y Session pooler seleccionados

Paso 3: crea una contraseña de cifrado

Esta es la clave que va a proteger tus copias. Genera una larga y aleatoria, por ejemplo con este comando en tu terminal:

openssl rand -base64 32

Copia el resultado y guárdalo en un lugar seguro.

Si pierdes esta clave, pierdes el acceso a todas las copias cifradas. No hay "recuperar contraseña" para esto: es cifrado simétrico, la clave es lo único que abre el archivo.

Paso 4: reparte la cadena de conexión en secretos y guárdalos en GitHub

La cadena que copiaste en el Paso 2 tiene esta forma:

postgresql://postgres.[referencia-del-proyecto]:[TU-CONTRASEÑA]@aws-[región].pooler.supabase.com:5432/postgres

Sepárala en sus cuatro partes:

  • Usuario: postgres.[referencia-del-proyecto]
  • Contraseña: [TU-CONTRASEÑA]
  • Host: aws-[región].pooler.supabase.com
  • Base de datos: postgres

Ahora ve a tu repositorio: Settings → Secrets and variables → Actions → New repository secret. Crea cuatro:

  • Nombre PGUSER → valor: el usuario.
  • Nombre PGPASSWORD → valor: la contraseña.
  • Nombre PGHOST → valor: el host.
  • Nombre PGDATABASE → valor: postgres.

Y uno más, la clave del Paso 3:

  • Nombre BACK_UP_ENCRYPTION_KEY → valor: la contraseña de cifrado del Paso 3.
Sidebar de Settings con Secrets and variables → Actions seleccionadoLista de los cinco secretos del repositorio

Paso 5: crea el archivo del workflow

Crea la carpeta .github/workflows/ y dentro un archivo backup.yml y copia dentro del archivo el siguiente código:

Ruta .github/workflows/backup.yml en GitHub
name: Supabase Backup

on:
  schedule:
    - cron: '0 8 * * *'
  workflow_dispatch:

jobs:
  backup:
    runs-on: ubuntu-latest
    steps:
      - name: Descargar el repositorio
        uses: actions/checkout@v5

      - name: Instalar herramientas necesarias
        run: |
          sudo apt-get update
          sudo apt-get install -y wget ca-certificates gnupg
          sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
          wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
          sudo apt-get update
          sudo apt-get install -y postgresql-client-17 gnupg
          echo "/usr/lib/postgresql/17/bin" >> $GITHUB_PATH

      - name: Crear la copia de seguridad
        run: /usr/lib/postgresql/17/bin/pg_dump --no-owner --no-privileges --clean --if-exists -f backup.sql
        env:
          PGHOST: ${{ secrets.PGHOST }}
          PGUSER: ${{ secrets.PGUSER }}
          PGPASSWORD: ${{ secrets.PGPASSWORD }}
          PGDATABASE: ${{ secrets.PGDATABASE }}

      - name: Cifrar la copia
        run: |
          mkdir -p backups/history
          gpg --batch --yes --passphrase "$BACK_UP_ENCRYPTION_KEY" \
              --symmetric --cipher-algo AES256 \
              -o "backups/history/$(date +%F).sql.gpg" backup.sql
          cp "backups/history/$(date +%F).sql.gpg" backups/latest.sql.gpg
          rm backup.sql
        env:
          BACK_UP_ENCRYPTION_KEY: ${{ secrets.BACK_UP_ENCRYPTION_KEY }}

      - name: Subir los cambios al repositorio
        run: |
          git config user.name "github-actions"
          git config user.email "actions@github.com"
          git add backups/
          git commit -m "Backup cifrado $(date +%F)" || echo "Sin cambios"
          git push
La diferencia clave frente a un backup sin cifrar: el archivo .sql se borra (rm backup.sql) justo después de cifrarlo, así que nunca llega a subirse al repositorio en texto plano. Solo sube la versión cifrada, .sql.gpg.

Paso 6: da permiso de escritura al workflow desde el repositorio, no desde tu cuenta

Settings → Actions → General → Workflow permissions → marca Read and write permissions → guarda.

Esa sección está casi al final de la página, después de "Actions permissions" y "Fork pull request workflows".

Sidebar de Settings con Actions abierto dentro de Code, planning, and automationPágina Workflow permissions con Read and write permissions marcado

Paso 7: pruébalo

Pestaña Actions → Supabase Backup → Run workflow. Comprueba que aparece el archivo backups/latest.sql.gpg en el repositorio.

Barra de navegación del repositorio con la pestaña Actions resaltada

Paso 8: cómo recuperar una copia cuando la necesites

Esta parte no necesita terminal.

  1. Descarga el archivo cifrado desde GitHub. Entra en tu repositorio → carpeta backups/. Descarga latest.sql.gpg (la más reciente) o el de la fecha que necesites dentro de backups/history/.
  2. Instala GPG Suite, una sola vez. Ve a gpgtools.org, descarga la app gratuita e instálala como cualquier programa de Mac.Página de descarga de GPG Suite en gpgtools.org
  3. Descifra el archivo. En Finder, busca el archivo .gpg que descargaste. Click derecho sobre él → Services ("Servicios") → OpenPGP: Decrypt File. Te va a pedir una contraseña: escribe la clave de cifrado, la que guardaste como BACK_UP_ENCRYPTION_KEY. Esto crea un archivo .sql normal y legible en la misma carpeta.
  4. Abre el archivo descifrado. Ábrelo con Antigravity, Cursor, Windsurf u otro editor de código, selecciona todo el contenido (Cmd + A) y cópialo (Cmd + C).
  5. Ve al SQL Editor de Supabase. Entra en el proyecto donde quieres restaurar los datos → menú izquierdo → SQL Editor → New query.
  6. Pega y ejecuta. Pega el contenido copiado (Cmd + V) y haz click en Run.
  7. Comprueba el resultado. Ve a Table Editor dentro de ese mismo proyecto y revisa que tus tablas tengan los datos esperados.
Aviso antes del paso 6: ese paso borra las tablas de esa base de datos y las vuelve a crear con los datos de la copia que estás restaurando. No se combina con lo que ya había: lo que hay ahora desaparece y queda sustituido por la versión del backup. Antes de ejecutarlo, confirma que estás en el proyecto correcto. En cuanto termines de usarlo, borra el archivo .sql descifrado de tu ordenador.

Bonus: que las copias antiguas no se acumulen para siempre

Crea en .github/workflows/ el archivo cleanup.yml y pega esto:

name: Supabase Backup Cleanup

on:
  schedule:
    - cron: '0 4 1 * *'
  workflow_dispatch:

jobs:
  cleanup:
    runs-on: ubuntu-latest
    steps:
      - name: Descargar el repositorio
        uses: actions/checkout@v5

      - name: Borrar las 10 copias más antiguas
        run: |
          cd backups/history
          ARCHIVOS=$(ls -1 *.sql.gpg 2>/dev/null | sort | head -n 10)
          if [ -z "$ARCHIVOS" ]; then
            echo "No hay archivos que borrar."
            exit 0
          fi
          echo "Borrando:"
          echo "$ARCHIVOS"
          echo "$ARCHIVOS" | xargs rm -f

      - name: Subir los cambios al repositorio
        run: |
          git config user.name "github-actions"
          git config user.email "actions@github.com"
          git add backups/history/
          git commit -m "Limpieza mensual: borradas 10 copias antiguas $(date +%F)" || echo "Sin cambios"
          git push

El día 1 de cada mes se borran los 10 backups más antiguos.

Cómo comprobar que funciona. Repite el Paso 7 (Pruébalo), pero esta vez eligiendo el workflow "Supabase Backup Cleanup".

Cómo cambiar el número de backups que se borran. Si en el futuro quieres guardar más o menos copias, cambia el 10 en head -n 10 a la cantidad de las copias que quieres que se borren.

Qué puedes hacer hoy: checklist

  1. Cifra el archivo antes de guardarlo (con gpg, como en esta guía, o con una herramienta equivalente como age).
  2. Activa la verificación en dos pasos en tu cuenta de GitHub.
  3. Manda las copias de seguridad a un segundo sitio independiente de GitHub (Google Drive, por ejemplo), para no depender de un único proveedor.
  4. Borra el archivo .sql descifrado de tu ordenador en cuanto termines de usarlo.
  5. Prueba la restauración al menos una vez, antes de necesitarla de verdad.

Conclusión

El plan gratuito de Supabase no incluye copias de seguridad. Eso no es una razón para no tenerlas: es la razón para crearlas tú mismo, con herramientas gratuitas que ya tienes a mano. Es media hora de trabajo, una sola vez y a partir de ahí es automático.

¿Quieres saber si tu app hecha con IA es segura?

Te comparto checklists, casos reales y tutoriales de seguridad.