[{"data":1,"prerenderedAt":1161},["ShallowReactive",2],{"blog-es-supabase-backup-github-action":3,"blog-index-es":815},{"id":4,"title":5,"body":6,"category":768,"cover":769,"coverAlt":770,"description":771,"draft":772,"extension":773,"faq":774,"image":792,"keywords":793,"meta":802,"navigation":803,"ogTitle":804,"path":805,"published":806,"seo":807,"stem":808,"tldr":809,"updated":813,"__hash__":814},"blog_es\u002Fblog\u002Fsupabase-backup-github-action.md","Backup gratis de Supabase con una GitHub Action, y la trampa",{"type":7,"value":8,"toc":752},"minimark",[9,13,21,24,29,40,49,57,60,64,72,82,85,139,146,153,157,160,177,191,197,200,203,207,216,225,233,242,245,249,252,255,335,338,341,346,349,357,360,364,377,398,404,407,410,416,422,459,465,468,472,475,478,515,518,522,530,548,552,555,571,579,584,592,601,607,610,614,617,645,649,654,697,710,714,744],[10,11,12],"p",{},"Tu proyecto de Supabase está en el plan gratuito, así que nada se copia a\nninguna parte, o está en Pro y cada copia que hace vive dentro de la cuenta que\nte preocupa perder. En un hilo justo sobre eso, alguien dijo que la respuesta es\nuna GitHub Action de backup de Supabase: un archivo pequeño en un repositorio\nque vuelca tu base de datos cada noche y no cuesta nada.",[10,14,15,16,20],{},"El consejo era bueno. Supabase publica el workflow él mismo, y para muchas apps\nes lo que conviene montar esta semana. Esta es la parte que esos hilos se\nsaltan: ",[17,18,19],"strong",{},"no cuesta dinero y aun así tiene un precio."," Cada ejecución descarga\ntu base de datos entera, y Supabase mide esa descarga.",[10,22,23],{},"Piénsalo como los datos de tu plan de móvil. Tu plan trae un cupo mensual, todo\nlo que hace tu app tira de él, y un backup es una descarga grande en el mismo\nplan. En el plan gratuito, una copia nocturna de una base cerca de su límite de\ntamaño se come el cupo de todo el mes en unos diez días. Eso, y un connection\nstring que GitHub no alcanza, son las dos cosas entre tú y un backup que\nfuncione, y ninguna de las dos está en la página de Supabase.",[25,26,28],"h2",{"id":27},"puedes-hacer-backup-de-supabase-gratis-con-una-github-action","¿Puedes hacer backup de Supabase gratis con una GitHub Action?",[10,30,31,32,39],{},"Sí, y Supabase documenta cómo. Su página sobre\n",[33,34,38],"a",{"href":35,"rel":36},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fdeployment\u002Fci\u002Fbackups",[37],"nofollow","backups automáticos con GitHub Actions","\nda un workflow que instala la CLI de Supabase, vuelca tus roles, tu esquema y\ntus datos en tres archivos y les hace commit de vuelta en el repositorio según\nun horario.",[10,41,42,43,48],{},"GitHub tampoco cobra por ello, dentro de unos límites. Un repositorio privado en\nGitHub Free recibe\n",[33,44,47],{"href":45,"rel":46},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Fbilling\u002Fconcepts\u002Fproduct-billing\u002Fgithub-actions",[37],"2.000 minutos de Actions al mes",",\ny un dump nocturno de una base pequeña gasta una parte pequeña de ellos.",[10,50,51,52,56],{},"Lo que obtienes es una copia que sale de Supabase cada noche y aterriza en los\nservidores de otra empresa. Eso es justo lo que los backups del propio Supabase\nno pueden darte, porque las copias diarias de un plan de pago\n",[33,53,55],{"href":54},"\u002Fblog\u002Fdownload-your-supabase-backup","se quedan dentro de la cuenta que protegen",".",[10,58,59],{},"Es la respuesta correcta cuando se cumplen tres cosas. Tu app ya vive en un\nrepositorio de GitHub, que es lo que pasa si activaste la sincronización con\nGitHub en Lovable o en un builder parecido. Editar un archivo YAML no te\npreocupa. Y tu base de datos es pequeña al lado del cupo de egress de tu plan.\nLas dos primeras ya las sabes. La tercera es aritmética, y tiene su propia\nsección más abajo.",[25,61,63],{"id":62},"el-workflow-con-el-horario-y-el-secret","El workflow, con el horario y el secret",[10,65,66,67,71],{},"Guarda esto como ",[68,69,70],"code",{},".github\u002Fworkflows\u002Fsupabase-backup.yml"," en un repositorio\nprivado que no contenga nada más:",[73,74,80],"pre",{"className":75,"code":77,"language":78,"meta":79},[76],"language-yaml","name: supabase-backup\n\non:\n  schedule:\n    - cron: '17 3 * * *' # cada día a las 03:17 UTC\n  workflow_dispatch:\n\njobs:\n  backup:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    env:\n      SUPABASE_DB_URL: ${{ secrets.SUPABASE_DB_URL }}\n    steps:\n      - uses: actions\u002Fcheckout@v7\n      - uses: supabase\u002Fsetup-cli@v3\n        with:\n          version: latest\n      - name: Back up roles\n        run: supabase db dump --db-url \"$SUPABASE_DB_URL\" -f roles.sql --role-only\n      - name: Back up schema\n        run: supabase db dump --db-url \"$SUPABASE_DB_URL\" -f schema.sql\n      - name: Back up data\n        run: >\n          supabase db dump --db-url \"$SUPABASE_DB_URL\" -f data.sql --use-copy --data-only\n          -x \"storage.buckets_vectors\" -x \"storage.vector_indexes\"\n      - uses: stefanzweifel\u002Fgit-auto-commit-action@v7\n        with:\n          commit_message: Supabase backup\n","yaml","",[68,81,77],{"__ignoreMap":79},[10,83,84],{},"Es el workflow de Supabase con tres cambios.",[86,87,88,99,123],"ul",{},[89,90,91,94,95,98],"li",{},[17,92,93],{},"Se ejecuta según el horario y cuando pulsas el botón, y en ningún otro\nmomento."," La versión de Supabase también se ejecuta con cada push y cada pull\nrequest a ",[68,96,97],{},"main",". Cada ejecución es una descarga completa de tu base, así que\nen un repositorio que además contiene tu app, cada cambio que publicaras\ngastaría el cupo de un backup.",[89,100,101,104,105,110,111,114,115,118,119,122],{},[17,102,103],{},"Se ejecuta a las 03:17, fuera de la hora en punto."," GitHub dice que las\nejecuciones programadas\n",[33,106,109],{"href":107,"rel":108},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions\u002Freference\u002Fworkflows-and-actions\u002Fevents-that-trigger-workflows#schedule",[37],"pueden retrasarse al inicio de cada hora",",\ny que con suficiente carga algunos trabajos en cola se descartan. El ejemplo de\nSupabase usa ",[68,112,113],{},"0 0 * * *",", que es una hora en punto. Las horas son UTC salvo que\nañadas un ",[68,116,117],{},"timezone",", y cualquier minuto distinto de ",[68,120,121],{},"0"," sirve.",[89,124,125,134,135,138],{},[17,126,127,128,133],{},"La línea de datos coincide con la\n",[33,129,132],{"href":130,"rel":131},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fmigrating-within-supabase\u002Fbackup-restore",[37],"guía de backup y restauración","\nactual de Supabase",", que añade dos exclusiones ",[68,136,137],{},"-x"," que la página del\nworkflow no tiene. Así los archivos que guardas son los que esperan las\ninstrucciones de restauración de Supabase.",[10,140,141,142,145],{},"Luego el secret. En el repositorio, abre Settings, luego Secrets and variables,\nluego Actions, y añade un secret de repositorio llamado ",[68,143,144],{},"SUPABASE_DB_URL",". Lo\nque va dentro decide si todo esto funciona, así que tiene la siguiente sección\npara él solo.",[10,147,148,149,152],{},"Cuando esté guardado, ejecuta el workflow a mano desde la pestaña Actions, para\nque la primera ejecución ocurra mientras miras. ",[68,150,151],{},"workflow_dispatch"," es la línea\nque te da el botón Run workflow.",[25,154,156],{"id":155},"qué-connection-string-va-en-el-secret","¿Qué connection string va en el secret?",[10,158,159],{},"El string del Session pooler, desde el botón Connect en la parte de arriba de tu\nproyecto de Supabase. Úsalo aunque la página del workflow de Supabase muestre la\nconexión directa en su ejemplo.",[10,161,162,163,166,167,170,171,176],{},"El motivo es IPv6, el tipo más nuevo de dirección de internet. La conexión\ndirecta de Supabase, el host que empieza por ",[68,164,165],{},"db."," y termina en ",[68,168,169],{},"supabase.co",",\n",[33,172,175],{"href":173,"rel":174},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fipv4-address",[37],"usa IPv6 por defecto",",\ny la misma página incluye GitHub Actions entre los servicios que solo aceptan\nIPv4. El runner recibe una dirección a la que no tiene camino, y el primer dump\nfalla antes de escribir un solo byte. El error dice que el nombre del host no se\npudo traducir, o que la red es inalcanzable, a menudo con una dirección larga\nllena de dos puntos al lado. Esa dirección es la IPv6. Parece una contraseña\nequivocada o una base caída, y la causa real es una red en la que el runner no\nestá.",[10,178,179,180,183,184,187,188,56],{},"La guía de backup y restauración de Supabase dice que uses por defecto el string\ndel Session pooler, y el directo solo si tu red admite IPv6 o pagas el\ncomplemento IPv4. El string del pooler se reconoce por tres cosas: su nombre de\nusuario es ",[68,181,182],{},"postgres."," seguido de la referencia de tu proyecto, su host termina\nen ",[68,185,186],{},"pooler.supabase.com"," y su puerto es ",[68,189,190],{},"5432",[192,193],"diagram",{"alt":194,"caption":195,"src":196},"Un runner de GitHub a la izquierda con dos caminos de salida. El de arriba lleva el host directo db.[ref].supabase.co, está marcado IPv6 y se detiene en un muro con una cruz antes de la base de datos. El de abajo lleva el host pooler.supabase.com, está marcado IPv4 y llega a la base con una marca de verificación.","El runner no tiene camino hasta la dirección IPv6 de la conexión directa. El Session pooler responde por IPv4 y llega a la misma base de datos.","\u002Fblog\u002Fsupabase-backup-github-action\u002Fwhich-string-reaches-the-runner-1600x620.png",[10,198,199],{},"La contraseña que lleva es la contraseña de tu base de datos, la que se puso al\ncrear el proyecto, y no una clave de API. Si nadie la apuntó, Supabase te deja\nrestablecerla en Database Settings; cualquier otra cosa que se conecte con la\nantigua deja de funcionar hasta que le des la nueva.",[10,201,202],{},"Ese string puede leer y cambiar cada fila de tu base de datos. Vive en el secret\ny en ningún otro sitio: nunca en el archivo del workflow, nunca en un mensaje de\ncommit y nunca pegado en un asistente de IA junto con el error por el que ibas a\npreguntar.",[25,204,206],{"id":205},"un-backup-de-supabase-cuenta-contra-mi-egress","¿Un backup de Supabase cuenta contra mi egress?",[10,208,209,210,215],{},"Sí, entero. Supabase cuenta como\n",[33,211,214],{"href":212,"rel":213},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fmanage-your-usage\u002Fegress",[37],"egress",",\nes decir, tráfico de salida, los datos que cualquiera de sus servicios envía\nhacia fuera, y un dump a través del pooler se registra como Shared Pooler Egress\ndentro del mismo cupo que tu tráfico de API, tus descargas de archivos y todo lo\ndemás que sirve tu app.",[10,217,218,219,224],{},"Volvamos al plan de móvil. El cupo se reinicia cada mes de facturación, cada\nservicio que usa tu app tira de él, y un backup es una descarga grande más.\nAdemás es un plan familiar: Supabase aplica el cupo a\n",[33,220,223],{"href":221,"rel":222},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fbilling-on-supabase",[37],"toda tu organización",",\nasí que todos los proyectos que hay en ella comparten el mismo cupo.",[10,226,227,228,232],{},"El 26 de septiembre de 2026, la página de precios de Supabase daba al plan\ngratuito 5 GB de egress al mes y un límite de 500 MB para la base de datos de\ncada proyecto, y al plan Pro 250 GB de egress. En el plan gratuito hay otros\n5 GB de cached egress, que cubre los archivos servidos desde la CDN de Supabase,\ny un backup nunca lo toca. Los demás límites del plan gratuito, y ",[33,229,231],{"href":230},"\u002Fblog\u002Fsupabase-free-plan-limits","lo que hace cada uno cuando lo cruzas",", tienen su propio artículo.",[10,234,235,236,241],{},"Pasarse del cupo en el plan gratuito no genera una factura. Supabase\n",[33,237,240],{"href":238,"rel":239},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fbilling-faq",[37],"te avisa y te da un periodo de gracia",",\ny si sigues pasándote, restringe todos los proyectos de la organización. Dice\nque eso puede significar peticiones a la API respondidas con un error 402, una\nbase de datos pasada a solo lectura o proyectos pausados. Para una app con\nclientes, es una caída que empezó tu backup.",[10,243,244],{},"Esto vale para cualquier backup que salga de Supabase, incluido el que vendemos\nnosotros. Una copia guardada fuera de la cuenta tiene que descargarse para\nllegar allí.",[25,246,248],{"id":247},"cada-cuánto-debería-ejecutarse-el-backup","¿Cada cuánto debería ejecutarse el backup?",[10,250,251],{},"Tan a menudo como tu cupo pueda pagar, y eso se reduce a una sola\nmultiplicación: el tamaño de tu base de datos por las ejecuciones del mes.",[10,253,254],{},"Supabase muestra el tamaño de tu base en el informe Database, dentro de\nObservability en tu proyecto. Un dump no mide exactamente eso. Deja fuera los\níndices, que se reconstruyen a partir de sus definiciones, y escribe cada valor\ncomo texto. Se acerca lo bastante para planificar, y es el número que puedes\nconsultar.",[256,257,258,277],"table",{},[259,260,261],"thead",{},[262,263,264,268,271,274],"tr",{},[265,266,267],"th",{},"Tamaño de la base",[265,269,270],{},"Diario (30 ejecuciones)",[265,272,273],{},"Dos veces por semana",[265,275,276],{},"Semanal",[278,279,280,295,308,322],"tbody",{},[262,281,282,286,289,292],{},[283,284,285],"td",{},"50 MB",[283,287,288],{},"1,5 GB",[283,290,291],{},"0,4 GB",[283,293,294],{},"0,2 GB",[262,296,297,300,303,306],{},[283,298,299],{},"100 MB",[283,301,302],{},"3 GB",[283,304,305],{},"0,9 GB",[283,307,291],{},[262,309,310,313,316,319],{},[283,311,312],{},"250 MB",[283,314,315],{},"7,5 GB",[283,317,318],{},"2,2 GB",[283,320,321],{},"1,1 GB",[262,323,324,327,330,333],{},[283,325,326],{},"500 MB",[283,328,329],{},"15 GB",[283,331,332],{},"4,3 GB",[283,334,318],{},[10,336,337],{},"Un mes tiene unas 4,3 semanas, y de ahí salen las dos últimas columnas.",[10,339,340],{},"En el plan gratuito, las dos cifras diarias de abajo gastan más que el cupo de\ntodo el mes antes de que tu app haya respondido una sola petición. Un horario\ndiario gasta los 5 GB completos con unos 160 MB, y el tráfico de tu propia app\nsale del mismo cupo, así que mira el egress del mes pasado en la página Usage de\ntu organización antes de elegir. El semanal cabe con cualquier tamaño que\npermita el plan gratuito.",[192,342],{"alt":343,"caption":344,"src":345},"Una base de datos con una marca de repetición junto a dos columnas de bloques: treinta copias en un mes a la izquierda, cuatro a la derecha. Una línea discontinua marca el cupo mensual. La columna izquierda la supera a un tercio de su altura y sus bloques por encima de la línea son ámbar. La derecha se queda muy por debajo, en turquesa.","Una base de datos en el límite de 500 MB del plan gratuito, con backup diario y semanal. La línea discontinua son los 5 GB de egress del plan gratuito para el mes.","\u002Fblog\u002Fsupabase-backup-github-action\u002Fthirty-copies-four-copies-1600x680.png",[10,347,348],{},"La línea de cron es lo único que cambias:",[73,350,355],{"className":351,"code":353,"language":354},[352],"language-text","17 3 * * *      cada día a las 03:17 UTC\n17 3 * * 1,4    lunes y jueves\n17 3 * * 0      domingos\n","text",[68,356,353],{"__ignoreMap":79},[10,358,359],{},"En Pro la aritmética casi deja de importar. 250 GB al mes pagan un dump diario\nde un proyecto de hasta unos 8 GB, que es el espacio en disco que el plan Pro\nincluye por proyecto.",[25,361,363],{"id":362},"por-qué-falla-mi-workflow-con-un-error-de-versión-de-pg_dump","¿Por qué falla mi workflow con un error de versión de pg_dump?",[10,365,366,367,370,371,373,374,376],{},"Porque el ",[68,368,369],{},"pg_dump"," que ejecutó es más antiguo que tu base de datos. Eso solo le\npasa a un workflow que llama a ",[68,372,369],{}," directamente en lugar de hacerlo a\ntravés de la CLI de Supabase. La CLI trae su propio ",[68,375,369],{},", y esa es una de\nlas razones por las que el workflow de arriba la usa.",[10,378,379,380,383,384,389,390,392,397],{},"El runner ",[68,381,382],{},"ubuntu-latest"," de GitHub viene con\n",[33,385,388],{"href":386,"rel":387},"https:\u002F\u002Fgithub.com\u002Factions\u002Frunner-images\u002Fblob\u002Fmain\u002Fimages\u002Fubuntu\u002FUbuntu2404-Readme.md",[37],"PostgreSQL 16 instalado",".\nLos proyectos de Supabase pueden usar Postgres 17, y Postgres documenta que\n",[68,391,369],{},[33,393,396],{"href":394,"rel":395},"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fapp-pgdump.html",[37],"no vuelca desde un servidor de una versión mayor más nueva que la suya",",\ny prefiere negarse a arriesgarse a un archivo defectuoso. La ejecución se\ndetiene con:",[73,399,402],{"className":400,"code":401,"language":354},[352],"pg_dump: error: aborting because of server version mismatch\npg_dump: detail: server version: 17.…; pg_dump version: 16.…\n",[68,403,401],{"__ignoreMap":79},[10,405,406],{},"La versión de tu proyecto está en Project Settings, luego General, si quieres\nconfirmarla. No hay nada mal en tus credenciales.",[10,408,409],{},"El arreglo son dos pasos. Añade el repositorio de paquetes del propio PostgreSQL\npara que el runner pueda instalar el cliente de la versión 17, y luego llama a\nese cliente por su ruta completa:",[73,411,414],{"className":412,"code":413,"language":78,"meta":79},[76],"- name: Install the Postgres 17 client\n  run: |\n    sudo apt-get install -y postgresql-common\n    sudo \u002Fusr\u002Fshare\u002Fpostgresql-common\u002Fpgdg\u002Fapt.postgresql.org.sh -y\n    sudo apt-get install -y postgresql-client-17\n- name: Back up\n  run: \u002Fusr\u002Flib\u002Fpostgresql\u002F17\u002Fbin\u002Fpg_dump \"$SUPABASE_DB_URL\" …\n",[68,415,413],{"__ignoreMap":79},[10,417,418,419,421],{},"Mantén después del connection string los argumentos que ya tenías. La ruta\ncompleta importa: en Ubuntu, el ",[68,420,369],{}," a secas es un envoltorio que elige una\nversión por ti, y el runner ya tiene una instalación de PostgreSQL 16 para que\nla elija.",[10,423,424,425,427,428,431,432,440,441,444,445,448,449,451,452,455,456,458],{},"El ",[68,426,369],{}," de la CLI también tiene versión, y no sale de tu proyecto. Sin un\n",[68,429,430],{},"supabase\u002Fconfig.toml"," junto al workflow, que es lo que pasa en un repositorio\nque no tiene nada más, la CLI\n",[33,433,436,437,439],{"href":434,"rel":435},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fcli\u002Fblob\u002F66ccc6f63a9a26b29c368698994a0843d23b80be\u002Fapps\u002Fcli\u002Fsrc\u002Fcommand-internal\u002Fdb-config.toml-read.ts#L176",[37],"usa ",[68,438,369],{}," 17",".\nEn un proyecto que sigue en Postgres 15, el ",[68,442,443],{},"data.sql"," que escribe lleva\nentonces ",[68,446,447],{},"SET transaction_timeout = 0",", un ajuste que Postgres 15 no tiene, y la\ncarga se detiene en esa línea en cualquier base de datos Postgres 15, incluido\nel proyecto del que salió el archivo. Lo reprodujimos el 4 de octubre de 2026\ncon ",[68,450,369],{}," 17.11 y Postgres 15.19. Si tu proyecto está en 15, añade una línea\nal bloque ",[68,453,454],{},"env"," del job para que la CLI use el ",[68,457,369],{}," que corresponde:",[73,460,463],{"className":461,"code":462,"language":78,"meta":79},[76],"env:\n  SUPABASE_DB_URL: ${{ secrets.SUPABASE_DB_URL }}\n  SUPABASE_DB_MAJOR_VERSION: '15'\n",[68,464,462],{"__ignoreMap":79},[10,466,467],{},"El backup en sí termina sin errores en los dos casos, así que sin esa línea la\ndiferencia solo aparece el día que cargas el archivo.",[25,469,471],{"id":470},"puedo-hacer-commit-del-backup-en-mi-repositorio","¿Puedo hacer commit del backup en mi repositorio?",[10,473,474],{},"En uno privado, sí. Es lo que hace el workflow de Supabase, y su página dice dos\nveces que nunca hagas backup de tus datos en un repositorio público.",[10,476,477],{},"Tres cosas sobre un repositorio como hogar de una base de datos, ninguna de\nellas en esa página:",[86,479,480,494,500],{},[89,481,482,485,486,488,489,493],{},[17,483,484],{},"Quien pueda leer el repositorio puede leer a tus usuarios."," ",[68,487,443],{},"\ncontiene cada fila: direcciones de correo, nombres, lo que guarden tus tablas,\ny ",[33,490,492],{"href":491},"\u002Fblog\u002Fsupabase-backup-auth-users","también tus cuentas",". Por eso el workflow\ntiene un repositorio propio sin nadie más dentro, y no el de tu app, que tu\nbuilder puede sincronizar y al que algún día quizá invites a un freelance.",[89,495,496,499],{},[17,497,498],{},"La copia de cada noche se queda en el historial."," Git guarda cada versión\nde cada archivo. Cuando alguien de tu clientela te pide borrar su cuenta, su\nfila sigue en cada commit anterior de ese repositorio hasta que reescribas su\nhistorial.",[89,501,502,505,506,511,512,514],{},[17,503,504],{},"Deja de funcionar a los 100 MiB."," GitHub avisa con archivos de más de\n50 MiB y\n",[33,507,510],{"href":508,"rel":509},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Frepositories\u002Fworking-with-files\u002Fmanaging-large-files\u002Fabout-large-files-on-github",[37],"bloquea los de más de 100 MiB",",\ny la misma página dice que Git no está pensado para manejar archivos SQL\ngrandes. La noche en que ",[68,513,443],{}," cruza esa línea, el paso de commit falla,\ny todas las ejecuciones siguientes fallan igual.",[10,516,517],{},"Cuando te acerques, el mismo workflow puede subir los tres archivos a un bucket\nde almacenamiento tuyo en lugar de hacer commit de ellos. O es el punto en que\nhacerlo tú mismo ha dejado de salir barato, que es donde empieza la última\nsección.",[25,519,521],{"id":520},"qué-no-copia-el-workflow","¿Qué no copia el workflow?",[10,523,524,525,529],{},"Tus archivos subidos. Supabase Storage guarda cada archivo fuera de la base de\ndatos y una fila que lo describe dentro, así que el dump lleva la fila y no la\nimagen. ",[33,526,528],{"href":527},"\u002Fblog\u002Fsupabase-storage-backup","Hacer backup de Storage"," es un trabajo\naparte, en cualquier camino que elijas.",[10,531,532,533,536,537,540,541,543,544,547],{},"Tus usuarios sí están. El dump de datos recorre el esquema ",[68,534,535],{},"auth"," donde viven\ntus cuentas, y buscar ",[68,538,539],{},"auth.users"," en ",[68,542,443],{}," te los muestra. El proyecto\nalrededor de la base de datos no está: Edge Functions, ajustes de proveedores de\nauth, claves de API y secrets son configuración y no datos, y\n",[33,545,546],{"href":54},"la lista de lo que no guarda ninguna de las dos copias","\nes la que conviene leer antes de necesitarla.",[25,549,551],{"id":550},"una-ejecución-en-verde-significa-que-el-backup-funcionó","¿Una ejecución en verde significa que el backup funcionó?",[10,553,554],{},"Significa que el trabajo terminó sin errores, que es una afirmación más pequeña.\nTres resultados muy distintos acaban con la misma marca verde:",[556,557,558,561,564],"ol",{},[89,559,560],{},"Un buen dump del proyecto correcto.",[89,562,563],{},"Un dump del proyecto equivocado, porque el secret tiene el string de una\ncopia de staging.",[89,565,566,567,570],{},"Un dump sin ninguna fila, porque alguien editó la línea de datos y se perdió\n",[68,568,569],{},"--data-only",", lo que la vuelve a convertir en el dump del esquema.",[10,572,573,574,578],{},"Un resultado no deja ninguna huella. Una ejecución programada que GitHub\ndescarta por carga no aparece como fallo, porque no hay ninguna ejecución que\npueda fallar. Y cuando una ejecución sí falla, GitHub envía el aviso a\n",[33,575,577],{"href":107,"rel":576},[37],"la persona que editó por última vez la línea de cron",".\nSi te lo montó un freelance, el correo sobre tu backup llega a su bandeja.",[192,580],{"alt":581,"caption":582,"src":583},"Un trabajo terminado con una marca verde. Sale una línea que se divide en dos paneles de archivo idénticos. En el archivo de arriba todas las filas están llenas. En el de abajo las filas se acaban tras dos y el resto son contornos discontinuos vacíos.","Los dos archivos salieron de una ejecución que terminó sin errores. Nada en la ejecución te dice cuál tienes.","\u002Fblog\u002Fsupabase-backup-github-action\u002Fgreen-run-short-file-1600x740.png",[10,585,586,587,591],{},"Solo una restauración los distingue. Reproduce los tres archivos en un proyecto\nde Supabase desechable o en uno local, compara el número de filas de las tablas\nque te importan con las reales e inicia sesión como un usuario real.\n",[33,588,590],{"href":589},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Cómo restaurar un backup de Supabase","\ntiene los comandos, en el orden que da Supabase. Hazlo una vez ahora, y otra\ncada vez que cambies el workflow.",[10,593,594,595,600],{},"También puedes dejar que cada ejecución se encargue de la restauración y del\nrecuento. Publicamos una versión de este workflow como una GitHub Action de\ncódigo abierto, ",[33,596,599],{"href":597,"rel":598},"https:\u002F\u002Fgithub.com\u002FReeve-page\u002Fsupabase-backup-action",[37],"Reeve-page\u002Fsupabase-backup-action",".\nHace los mismos tres dumps, guarda la copia como artefacto\ndel workflow o en un bucket de S3 o R2, después la reproduce en una base de datos\nde Supabase desechable en el runner y compara el número de filas de cada tabla\ncon el archivo. La ejecución solo sale en verde cuando cada tabla volvió con las\nfilas que tiene el archivo:",[73,602,605],{"className":603,"code":604,"language":78,"meta":79},[76],"- uses: Reeve-page\u002Fsupabase-backup-action@v1\n  with:\n    db-url: ${{ secrets.SUPABASE_DB_URL }}\n",[68,606,604],{"__ignoreMap":79},[10,608,609],{},"Es gratuita y tiene licencia MIT. Cada ejecución sigue descargando la base de\ndatos entera, así que el cálculo de egress de arriba se le aplica tal cual, y\nprobar el inicio de sesión sigue siendo cosa tuya.",[25,611,613],{"id":612},"cuándo-debería-dejar-de-hacerlo-yo-mismo","¿Cuándo debería dejar de hacerlo yo mismo?",[10,615,616],{},"Cuando la aritmética deja de cuadrar, cuando el archivo ya no cabe en el\nrepositorio o cuando nadie restaura las copias. Basta con una de las tres.",[86,618,619,625,633,639],{},[89,620,621,624],{},[17,622,623],{},"Tu base de datos ha superado el cupo gratuito."," Pro sube el egress a 250 GB\ny añade los backups diarios del propio Supabase, guardados siete días, que se\nrestauran con un botón. Deja el workflow funcionando a su lado, porque esas\ncopias viven dentro de la cuenta.",[89,626,627,632],{},[17,628,629,631],{},[68,630,443],{}," se acerca a 100 MiB."," Pasarlo a un bucket es más YAML, y más\ncosas que alguien tiene que mantener funcionando.",[89,634,635,638],{},[17,636,637],{},"Nadie ha restaurado nunca una copia."," El workflow seguirá escribiendo\narchivos, se abran o no.",[89,640,641,644],{},[17,642,643],{},"Tus usuarios suben archivos."," El workflow no llega a ellos, y el trabajo\nque sí llega es otro más que mantener vivo.",[25,646,648],{"id":647},"dónde-encaja-reeve-care","Dónde encaja Reeve Care",[10,650,651],{},[17,652,653],{},"Care hace la copia según un horario, la guarda fuera de tu cuenta de Supabase\ny comprueba cada copia antes de que cuente.",[86,655,656,662,668,674,680],{},[89,657,658,661],{},[17,659,660],{},"A diario en Care, y más a menudo en los planes superiores",", sin nada en tu\nrepositorio y sin ningún connection string en una CI.",[89,663,664,667],{},[17,665,666],{},"Releída y contada."," Cada copia se abre y se cuenta frente a lo que entró, y\nla fecha de tu panel es la de la última copia que pasó esa comprobación, nunca\nla de la última ejecución.",[89,669,670,673],{},[17,671,672],{},"Tus cuentas van dentro",", y tus archivos subidos también vienen en cuanto\nconectas una credencial de Storage.",[89,675,676,679],{},[17,677,678],{},"Restaurar es un botón",", y antes de reemplazar nada se hace una copia del\nestado actual.",[89,681,682,685,686,689,690,692,693,696],{},[17,683,684],{},"Cualquier copia se descarga como zip"," con ",[68,687,688],{},"schema.sql",", ",[68,691,443],{}," y\n",[68,694,695],{},"roles.sql",", los mismos tres archivos que hace este workflow, más el número de\nfilas de cada tabla.",[10,698,699,700,704,705,709],{},"Care guarda una copia de tu base de datos de Supabase. La copia, la comprobación\ny la restauración están dibujadas paso a paso en la\n",[33,701,703],{"href":702},"\u002Fsupabase-backups","página de backups de Supabase",", y\n",[33,706,708],{"href":707},"\u002Fpricing","qué incluye cada plan"," está en la página de precios.",[25,711,713],{"id":712},"qué-hacer-esta-semana","Qué hacer esta semana",[715,716,717],"key-takeaways",{},[86,718,719,722,727,730,738,741],{},[89,720,721],{},"Consulta el tamaño de tu base de datos y el egress del mes pasado, y elige el horario con la tabla antes de escribir la línea de cron.",[89,723,724,725,56],{},"Crea un repositorio privado que no contenga más que el workflow, y pon el string del Session pooler en su secret ",[68,726,144],{},[89,728,729],{},"Si empezaste con el ejemplo de Supabase, borra los disparadores de push y pull request y saca el cron de la hora en punto.",[89,731,732,733,485,735,737],{},"Ejecútalo una vez a mano desde la pestaña Actions y busca en ",[68,734,443],{},[68,736,539],{}," y una tabla que sepas que tiene filas.",[89,739,740],{},"Restaura una copia en un proyecto desechable e inicia sesión como un usuario real.",[89,742,743],{},"Copia tus archivos de Storage con un trabajo aparte.",[10,745,746,747,751],{},"Antes de cerrar esta pestaña, abre en Supabase la página Usage de tu\norganización y lee el egress del mes pasado. Esa cifra, al lado del tamaño de tu\nbase de datos, es la que elige tu línea de cron. Y si todavía estás comparando\nel camino gratuito con los de pago,\n",[33,748,750],{"href":749},"\u002Fblog\u002Fsupabase-backup-tools-compared","los cuatro tipos de herramienta de backup de Supabase","\nestán comparados uno al lado del otro.",{"title":79,"searchDepth":753,"depth":753,"links":754},3,[755,757,758,759,760,761,762,763,764,765,766,767],{"id":27,"depth":756,"text":28},2,{"id":62,"depth":756,"text":63},{"id":155,"depth":756,"text":156},{"id":205,"depth":756,"text":206},{"id":247,"depth":756,"text":248},{"id":362,"depth":756,"text":363},{"id":470,"depth":756,"text":471},{"id":520,"depth":756,"text":521},{"id":550,"depth":756,"text":551},{"id":612,"depth":756,"text":613},{"id":647,"depth":756,"text":648},{"id":712,"depth":756,"text":713},"Backups","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcover-1200x630.png","Una base de datos en un recinto de Supabase, un tubo por un contador con la aguja en la franja ámbar y una fila de archivos nocturnos.","Un backup de Supabase con GitHub Action es gratis y sirve a muchas apps. El workflow, el connection string correcto y el egress de cada ejecución.",false,"md",[775,778,781,783,786,789],{"q":776,"a":777},"¿Puedo hacer backup de Supabase gratis?","Sí. Supabase documenta un workflow de GitHub Actions que instala su CLI, vuelca tus roles, tu esquema y tus datos en tres archivos según un horario y les hace commit en el repositorio. Un repositorio privado en GitHub Free recibe 2.000 minutos de Actions al mes, y un dump nocturno de una base pequeña gasta una parte pequeña de ellos. Lo que el backup sí gasta es tu cupo de egress en Supabase, porque cada ejecución descarga la base entera.",{"q":779,"a":780},"¿Cada cuánto debería ejecutarse un cron de backup de Supabase?","Tan a menudo como tu cupo de egress pueda pagar. Multiplica el tamaño de tu base por las ejecuciones del mes: una base de 100 MB volcada a diario mueve unos 3 GB, y una de 500 MB unos 15 GB. El plan gratuito incluye 5 GB para toda la organización, compartidos con el tráfico de tu propia app. Pon el trabajo en un minuto que no sea la hora en punto, porque GitHub dice que las ejecuciones programadas al inicio de cada hora pueden retrasarse, y algunas descartarse.",{"q":206,"a":782},"Sí. Supabase cuenta como egress los datos que cualquiera de sus servicios envía hacia fuera, y un dump a través del connection pooler se registra como Shared Pooler Egress dentro del mismo cupo que tu tráfico de API. El cupo pertenece a toda la organización, no a un solo proyecto. En el plan gratuito, pasarse de él una y otra vez termina en restricciones para todos los proyectos de la organización.",{"q":784,"a":785},"¿Por qué falla mi workflow de backup en la primera ejecución?","Hay dos fallos propios de este montaje. El primero es el connection string: la conexión directa de Supabase usa IPv6 salvo que pagues el complemento IPv4, y Supabase incluye GitHub Actions entre los servicios que solo llegan a IPv4, así que usa el string del Session pooler. El segundo afecta a los workflows que llaman a pg_dump directamente: el cliente PostgreSQL 16 del runner se niega a volcar un proyecto en Postgres 17 y se detiene con aborting because of server version mismatch.",{"q":787,"a":788},"¿Puedo hacer commit de mi backup de Supabase en mi repositorio de GitHub?","En uno privado, sí, que es lo que hace el workflow de Supabase. En uno público nunca, y Supabase lo dice dos veces en la misma página. Dale un repositorio propio que nadie más pueda leer, porque el archivo de datos contiene las direcciones de correo de tus usuarios. Y cuenta con tener que moverlo cuando la base crezca: GitHub avisa con archivos de más de 50 MiB y rechaza los de más de 100 MiB.",{"q":790,"a":791},"¿Cómo sé si el archivo de backup sirve?","Restáuralo. Una ejecución en verde significa que el trabajo terminó sin errores, y un dump del proyecto equivocado o un dump sin ninguna fila terminan igual. Reproduce los tres archivos en un proyecto de Supabase desechable o en uno local, compara el número de filas de las tablas que te importan e inicia sesión como un usuario real. Esa es la comprobación que te dice si el archivo se abre.","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",[794,795,796,797,798,799,800,801],"supabase backup github action","automatizar backup supabase","backup supabase cron","backup gratis supabase","supabase pg_dump github actions","backup programado supabase","workflow backup supabase","backup automatico supabase plan gratuito",{},true,"Backup gratis de Supabase con una GitHub Action","\u002Fblog\u002Fsupabase-backup-github-action","2026-09-27",{"title":5,"description":771},"blog\u002Fsupabase-backup-github-action",[810,811,812],"Una GitHub Action de backup de Supabase ejecuta la CLI de Supabase según un horario y hace commit del dump en un repositorio privado. No cuesta nada, y para muchas apps es la respuesta correcta.","Cada ejecución descarga tu base de datos entera, y Supabase lo cuenta como egress. El plan gratuito incluye 5 GB al mes para toda la organización, y un dump diario de una base cerca del límite de 500 MB gasta unas tres veces eso.","El ejemplo del propio Supabase se conecta con un string que los runners de GitHub no alcanzan. Pon el string del Session pooler en el secret y restaura una copia antes de fiarte del resto.","2026-10-05","FJ71j7PgoocO3Q4dmeRrLoY8bAwSn4zI2_H4Rs0NDxQ",[816,823,829,835,841,847,852,858,864,870,876,882,887,893,894,899,904,910,916,921,927,933,939,945,951,957,963,969,974,980,986,992,998,1004,1010,1016,1022,1028,1034,1040,1046,1051,1057,1063,1069,1075,1081,1087,1093,1098,1104,1110,1116,1122,1127,1133,1139,1145,1150,1156],{"path":817,"title":818,"description":819,"published":820,"category":821,"image":822,"draft":772},"\u002Fblog\u002Fbase44-security-scan","Escaneo de seguridad de Base44: lo que solo él ve","El escaneo de seguridad de Base44 revisa siete tipos de problema desde dentro. Esta es la mitad que lee y nadie más puede leer, y la mitad que nunca mira.","2026-10-10","Fundamentos de seguridad","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":824,"title":825,"description":826,"published":827,"category":821,"image":828,"draft":772},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Tu clave API se filtró. El orden en el que hay que actuar","Una clave API se filtró y no sabes por dónde empezar. No todas las claves de tu frontend lo son, y el orden importa más que la velocidad.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":830,"title":831,"description":832,"published":833,"category":821,"image":834,"draft":772},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sin desactivar RLS","\"Infinite recursion detected in policy for relation\" significa que tu policy preguntó a la tabla que protege. Así se rompe el círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":836,"title":837,"description":838,"published":839,"category":821,"image":840,"draft":772},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" en Supabase, y el arreglo equivocado","\"No API key found in request\" significa que tu petición llegó a Supabase sin clave. Casi todas las respuestas apuntan a las reglas de tu base de datos.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":842,"title":843,"description":844,"published":845,"category":821,"image":846,"draft":772},"\u002Fblog\u002Fis-base44-safe","¿Es seguro Base44? Lo que vimos en 5.442 apps Base44","¿Es seguro Base44? Pasamos nueve comprobaciones a 5.442 apps Base44 en producción. Casi todas sacaron B por motivos que su dueño nunca eligió.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":848,"title":849,"description":850,"published":813,"category":821,"image":851,"draft":772},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Ocultar una clave API: muévela a una Edge Function de Supabase","Ocultar una clave API significa sacarla del navegador, y una Edge Function de Supabase es el sitio más pequeño donde ponerla. Dos pasos importan más.","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":853,"title":854,"description":855,"published":856,"category":821,"image":857,"draft":772},"\u002Fblog\u002Fenv-file-exposed-on-your-server","¿Tu archivo .env está expuesto? Las doce rutas a revisar","¿Tu archivo .env está expuesto en tu propio servidor web? Doce direcciones te lo dicen, y un acierto significa que todo lo que contiene ya es público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":859,"title":860,"description":861,"published":862,"category":821,"image":863,"draft":772},"\u002Fblog\u002Fis-v0-safe","Seguridad de v0: las 1.790 aplicaciones escaneadas sacaron una A","Seguridad de v0, medida en 1.790 aplicaciones v0 en vivo: todas sacaron A. Solo 17 nombraban una base de datos, y eso es casi todo lo que mide la A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":865,"title":866,"description":867,"published":868,"category":821,"image":869,"draft":772},"\u002Fblog\u002Fis-bolt-safe","¿Es seguro Bolt? Lo que vimos en 1.123 aplicaciones Bolt","¿Es seguro Bolt? Pasamos 1.123 aplicaciones Bolt en vivo por nueve comprobaciones. El hosting salió limpio. Los hallazgos eran claves y tablas abiertas dentro.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":871,"title":872,"description":873,"published":874,"category":821,"image":875,"draft":772},"\u002Fblog\u002Fis-supabase-down-or-your-app","¿Supabase está caído o es tu app? Cómo distinguirlo","¿Supabase está caído o es tu app? Un proyecto pausado, una base de datos llena y un fallo tuyo parecen lo mismo. Cuatro comprobaciones los separan.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":877,"title":878,"description":879,"published":880,"category":821,"image":881,"draft":772},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","¿Supabase cifra mis datos? Sí. Esto es lo que detiene","¿Supabase cifra los datos? Sí: AES-256 en reposo, TLS en tránsito, SOC 2 e ISO 27001. Qué cubre cada uno, y la fuga que ninguno de ellos detiene.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":230,"title":883,"description":884,"published":885,"category":821,"image":886,"draft":772},"¿Cuánto cuesta Supabase? Los límites del plan gratuito","Los límites del plan gratuito de Supabase: 500 MB de base de datos, 5 GB de egress y ningún backup. Qué pasa en cada uno y qué cambia Pro por $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":888,"title":889,"description":890,"published":891,"category":768,"image":892,"draft":772},"\u002Fblog\u002Ftest-your-supabase-backup","Prueba tu backup de Supabase antes del día que lo necesites","Cómo probar tu backup de Supabase: restaurarlo en un proyecto de prueba, contar filas, iniciar sesión y buscar la línea que le falta a un archivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":805,"title":5,"description":771,"published":806,"category":768,"image":792,"draft":772},{"path":54,"title":895,"description":896,"published":897,"category":768,"image":898,"draft":772},"Por qué no puedes descargar tu backup de Supabase","No puedes descargar tu backup de Supabase en un proyecto actual: la copia diaria es una instantánea física. Cómo comprobarlo y tener tu propia copia.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":900,"title":901,"description":902,"published":897,"category":821,"image":903,"draft":772},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": el grant que falta","Desde el 30 de octubre, una tabla nueva de Supabase responde \"permission denied for table\" hasta que le das acceso. El grant del email es la mitad del arreglo.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":905,"title":906,"description":907,"published":908,"category":821,"image":909,"draft":772},"\u002Fblog\u002Fopen-api-endpoint-exposed","¿Un endpoint de API abierto es un problema? Mira el JSON","Tu escaneo señaló un endpoint de API abierto. Que importe depende de lo que devolvió, y la mayoría de los que encontramos eran de la plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":911,"title":912,"description":913,"published":914,"category":821,"image":915,"draft":772},"\u002Fblog\u002Flovable-security-scan","Escaneo de seguridad de Lovable: lo que no puede probar","Escaneo de seguridad de Lovable: qué revisan el Quick scan y el Deep scan, cuándo corre cada uno, y lo único que ningún escaneo desde dentro puede probar.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":491,"title":917,"description":918,"published":919,"category":768,"image":920,"draft":772},"Por qué tu dump de Supabase no tiene usuarios dentro","Ejecuta supabase db dump por sí solo y obtienes la forma de tu base de datos y ninguna de sus filas, sin el esquema auth donde viven tus usuarios.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":922,"title":923,"description":924,"published":925,"category":821,"image":926,"draft":772},"\u002Fblog\u002Fdomain-and-certificate-expiry","Dominio caducado, web caída: qué pasa a partir de ahora","Tu dominio caducó y tu web está caída. Aquí tienes el reloj que acaba de arrancar, por qué el certificado es el menor problema, y cómo comprobar ambos.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":928,"title":929,"description":930,"published":931,"category":821,"image":932,"draft":772},"\u002Fblog\u002Fis-lovable-safe","¿Es seguro Lovable? Lo que vimos en 18.554 aplicaciones Lovable","¿Es seguro Lovable? Pasamos 18.554 aplicaciones Lovable por nueve comprobaciones. La plataforma fue la más limpia de cinco. Los hallazgos estaban dentro.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":934,"title":935,"description":936,"published":937,"category":821,"image":938,"draft":772},"\u002Fblog\u002Fvibe-coded-app-security-checklist","La lista de seguridad del vibe coding, en nueve comprobaciones","Una lista de seguridad del vibe coding con nueve puntos, cada uno verificable en tu app desde fuera por cualquiera, y cada uno con una prueba de una línea.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":940,"title":941,"description":942,"published":943,"category":821,"image":944,"draft":772},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Una clave secreta de Stripe en tu frontend puede mover dinero","Una clave secreta de Stripe expuesta en tu frontend puede reembolsar, cobrar y leer cada ficha de cliente que tienes. Tu clave pk_live_ sí debe estar ahí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":946,"title":947,"description":948,"published":949,"category":821,"image":950,"draft":772},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variables de entorno de Vite expuestas: el prefijo dice publica esto","Variables de entorno de Vite expuestas en tu app: hicieron lo que pedía el prefijo. VITE_ y NEXT_PUBLIC_ significan publica esto, y la IA nunca supo el coste.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":952,"title":953,"description":954,"published":955,"category":821,"image":956,"draft":772},"\u002Fblog\u002Fbase44-source-maps","Seguridad en Base44: qué marca un escaneo y qué te toca arreglar a ti","Seguridad en Base44 en 5.438 apps escaneadas: tres hallazgos en casi todas son de la plataforma, el source map es la insignia de Base44 y lo tuyo es poco.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":958,"title":959,"description":960,"published":961,"category":821,"image":962,"draft":772},"\u002Fblog\u002Fis-cursor-ai-safe","¿Es seguro Cursor AI? El editor, el código y la app que publicaste","¿Es seguro Cursor AI? Tres preguntas en una búsqueda: qué guarda Cursor, en qué falla el código que escribe y si la app que publicaste está abierta.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":964,"title":965,"description":966,"published":967,"category":821,"image":968,"draft":772},"\u002Fblog\u002Fis-replit-safe","¿Es seguro Replit? Lo que vimos en 3.042 aplicaciones Replit en vivo","¿Es seguro Replit? Pasamos 3.042 aplicaciones Replit en vivo por nueve comprobaciones externas. Los hallazgos estaban en la aplicación publicada, no en el host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":527,"title":970,"description":971,"published":972,"category":768,"image":973,"draft":772},"Supabase storage backup: tu copia de la base no tiene archivos","Un Supabase storage backup es una tarea aparte. Las copias de la base guardan la lista de tus archivos y ninguno de ellos, así que cada upload queda roto.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":975,"title":976,"description":977,"published":978,"category":768,"image":979,"draft":772},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery de Supabase: precio y límites","El point-in-time recovery de Supabase rebobina tu base de datos a cualquier segundo de la última semana. Cuesta $100 al mes sobre Pro y solo cubre la base.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":981,"title":982,"description":983,"published":984,"category":768,"image":985,"draft":772},"\u002Fblog\u002Fsupabase-project-paused-recover","¿Proyecto de Supabase pausado? Tus datos siguen ahí","Supabase pausó tu proyecto tras una semana sin actividad. No se ha borrado nada, Restaurar está junto al nombre y tienes un año antes de que eso cambie.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":987,"title":988,"description":989,"published":990,"category":821,"image":991,"draft":772},"\u002Fblog\u002Fsafest-ai-app-builder","¿Qué builder de apps con IA es más seguro? 30.998 apps escaneadas","¿Qué builder de apps con IA es más seguro? Escaneamos 30.998 apps activas de Lovable, Base44, Replit, v0 y Bolt. El builder no es lo que decide tu nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":993,"title":994,"description":995,"published":996,"category":821,"image":997,"draft":772},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Activa Row Level Security en cada tabla de Supabase y compruébalo","Activar Row Level Security en Supabase sin política cierra la tabla del todo. Una política sin el interruptor no hace nada. Aquí tienes el SQL y la prueba.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":999,"title":1000,"description":1001,"published":1002,"category":821,"image":1003,"draft":772},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": lo que el aviso no ve","Supabase marca \"RLS disabled in public\" como error. No dice nada de la política de lectura que deja tu tabla igual de abierta a cualquiera.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1005,"title":1006,"description":1007,"published":1008,"category":821,"image":1009,"draft":772},"\u002Fblog\u002Frotate-supabase-service-role-key","Cómo rotar una clave service_role de Supabase filtrada","Supabase dice que primero cierres la fuga. Otras guías dicen que rotes ya. Cuál es lo correcto depende de dónde se filtró tu clave service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1011,"title":1012,"description":1013,"published":1014,"category":821,"image":1015,"draft":772},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Escáneres de seguridad vibe coding comparados, el nuestro incluido","El mejor escáner de seguridad para vibe coding depende de tres preguntas que ninguna lista de funciones responde. Diez herramientas, con precios.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1017,"title":1018,"description":1019,"published":1020,"category":821,"image":1021,"draft":772},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: haz tú mismo las cinco comprobaciones","Un Supabase security checker lee tu app publicada en lugar de la configuración de tu proyecto. Estas son las cinco comprobaciones y cómo hacer cada una.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1023,"title":1024,"description":1025,"published":1026,"category":821,"image":1027,"draft":772},"\u002Fblog\u002Fvibe-coding-security-scanner","Escáner de seguridad para vibe coding: qué se le escapa","Un escáner de seguridad para vibe coding lee tu app en vivo desde fuera. Qué cubre eso, las cuatro cosas que no puede ver y cómo leer el resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1029,"title":1030,"description":1031,"published":1032,"category":821,"image":1033,"draft":772},"\u002Fblog\u002Fmissing-security-headers","Faltan cabeceras de seguridad: cuándo importa de verdad","Que falten cabeceras de seguridad es el hallazgo que más imprime nuestro escáner. Contra qué protegen y cuándo son la línea menos urgente de tu informe.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1035,"title":1036,"description":1037,"published":1038,"category":821,"image":1039,"draft":772},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Tu clave de API de OpenAI está expuesta en tu frontend. Rótala.","Una clave de API de OpenAI expuesta en tu frontend no se puede atar a un dominio. Rótala hoy, mueve la llamada a tu servidor y limita el gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1041,"title":1042,"description":1043,"published":1044,"category":821,"image":1045,"draft":772},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Clave de API expuesta en el frontend: qué llevan 30.998 apps","Una clave de API expuesta en tu frontend suele ser una clave de Google Maps. Escaneamos 30.998 apps vibe-coded y contamos qué secretos se filtran de verdad.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":749,"title":1047,"description":1048,"published":1049,"category":768,"image":1050,"draft":772},"Herramientas de backup de Supabase comparadas, la nuestra incluida","Cuatro tipos de herramienta de backup de Supabase, qué copia cada una y cuándo una GitHub Action gratuita le gana a pagar a cualquiera, nosotros incluidos.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1052,"title":1053,"description":1054,"published":1055,"category":821,"image":1056,"draft":772},"\u002Fblog\u002Freplit-secrets-explained","Cómo usar secrets en Replit, y qué se publica de todos modos","Cómo usar secrets en Replit: añadir uno, leerlo y arreglar las dos causas del undefined. Y las claves que la herramienta Secrets no puede mantener privadas.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1058,"title":1059,"description":1060,"published":1061,"category":768,"image":1062,"draft":772},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups del plan gratuito de Supabase: cómo hacer uno sin terminal","No hay backups en el plan gratuito de Supabase: la copia tienes que hacerla tú. Cómo sacarla desde el panel y qué deja fuera la vía CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1064,"title":1065,"description":1066,"published":1067,"category":821,"image":1068,"draft":772},"\u002Fblog\u002Fis-supabase-secure","¿Supabase es seguro? Sí. Tu proyecto es otra pregunta","¿Supabase es seguro? La plataforma está auditada, cifrada y sometida a pentests. Su propia documentación dice dónde termina eso y empiezan tus ajustes.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1070,"title":1071,"description":1072,"published":1073,"category":821,"image":1074,"draft":772},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Dónde están tus claves API de Supabase: anon, service_role y URL","La URL del proyecto, la clave anon y la clave service_role están en una sola página del panel. Aquí tienes dónde está, y cuál de los cuatro va en tu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1076,"title":1077,"description":1078,"published":1079,"category":821,"image":1080,"draft":772},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy en Supabase. ¿Y ahora?","\"New row violates row-level security policy\" significa que Supabase rechazó una escritura. El arreglo rápido vuelve a abrir la tabla para cualquiera.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1082,"title":1083,"description":1084,"published":1085,"category":821,"image":1086,"draft":772},"\u002Fblog\u002Fcors-wildcard-security-risk","¿Es un comodín CORS un riesgo de seguridad? Casi nunca.","¿Es un comodín CORS un riesgo de seguridad? Casi siempre es el ajuste por defecto de tu builder y no entrega nada que tu servidor no diera ya a cualquiera.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1088,"title":1089,"description":1090,"published":1091,"category":768,"image":1092,"draft":772},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase branching no es un backup. Solo va hacia adelante.","Por qué el branching de Supabase no es un backup: una rama arranca sin tus datos y un merge solo mueve el esquema. Para qué sirve y qué usar en su lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":589,"title":1094,"description":1095,"published":1096,"category":768,"image":1097,"draft":772},"Cómo restaurar un backup de Supabase, y qué se rompe después","Cómo restaurar un backup de Supabase desde el panel o desde un archivo de volcado, qué reemplaza la restauración y por qué tu app puede seguir rota al terminar.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1099,"title":1100,"description":1101,"published":1102,"category":821,"image":1103,"draft":772},"\u002Fblog\u002Fsupabase-storage-bucket-public","Tu bucket de Supabase Storage es público. ¿Es un problema?","Un bucket público de Supabase Storage significa que quien tenga la URL de un archivo puede abrirlo. No significa que alguien pueda listar lo que hay dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1105,"title":1106,"description":1107,"published":1108,"category":821,"image":1109,"draft":772},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","¿Es un problema una clave de API de Google en tu frontend?","Una clave de API de Google en tu frontend es la clave que más encuentra nuestro escáner, y casi siempre no pasa nada. Un ajuste gratuito decide cuál es cuál.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1111,"title":1112,"description":1113,"published":1114,"category":768,"image":1115,"draft":772},"\u002Fblog\u002Fai-agent-deleted-my-database","Un agente de IA borró mis datos de Supabase. ¿Qué puedo recuperar?","Un agente de IA borró datos de tu base. Lo que puedes recuperar ya estaba decidido antes de que se ejecutara, y los próximos minutos deciden el resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1117,"title":1118,"description":1119,"published":1120,"category":821,"image":1121,"draft":772},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","¿Puede cualquiera leer tu base de datos Supabase? 3.680 apps","¿Puede cualquiera leer tu base de datos Supabase sin iniciar sesión? Escaneamos 30.998 apps activas hechas con builders de IA y medimos cuántas dicen que sí.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1123,"title":1124,"description":1125,"published":1120,"category":821,"image":1126,"draft":772},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expuestos: tu app está publicando su código original","Un source map expuesto deja que cualquiera lea el código original de tu app, comentarios incluidos. La comprobación de 30 segundos y lo que de verdad importa.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1128,"title":1129,"description":1130,"published":1131,"category":821,"image":1132,"draft":772},"\u002Fblog\u002Fsupabase-new-api-keys","Las nuevas claves de API de Supabase: ¿cuál va en tu app?","Supabase sustituyó anon y service_role por claves publicables y secretas. ¿Cuál pertenece a tu app y cuál no debe estar nunca?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1134,"title":1135,"description":1136,"published":1137,"category":768,"image":1138,"draft":772},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","¿Supabase respalda mi base de datos? Depende de tu plan.","¿Supabase respalda tu base de datos? A diario en los planes de pago, y nada en el gratuito. Cómo saber cuál tienes y qué es lo que esa copia no cubre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1140,"title":1141,"description":1142,"published":1143,"category":821,"image":1144,"draft":772},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security está activado. Tu tabla sigue pública.","Activar Supabase Row Level Security no protege una tabla. Lo hacen tus políticas, y la que arregló tu app rota puede dejar entrar a cualquiera.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1146,"title":1147,"description":1148,"published":1143,"category":768,"image":1149,"draft":772},"\u002Fblog\u002Fversion-history-is-not-a-backup","El historial de versiones no es un backup. No recupera una tabla.","Lovable y Bolt guardan un historial de versiones de tu código. Tu base de datos es un servicio aparte, y volver atrás no te devuelve tus datos.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1151,"title":1152,"description":1153,"published":1154,"category":768,"image":1155,"draft":772},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Tres formas de respaldar una base Supabase, y qué falta en cada una","El panel, pg_dump y un servicio gestionado. Qué guarda de verdad cada uno, qué deja fuera sin avisar y cuál sobrevive a perder la cuenta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1157,"title":1158,"description":1159,"published":1154,"category":821,"image":1160,"draft":772},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Qué claves de API son seguras en el navegador y cuáles no","Tu clave anon de Supabase está pensada para ser pública. Tu clave service_role no, y se salta todas las reglas que pongas. Cómo distinguirlas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1791618971497]