Publicar en YaDominios Cloud: guía técnica completa (para desarrolladores e IA)
Actualizado: 2026-07-31 · YaDominios
YaDominios Cloud publica un repositorio de GitHub como sitio en vivo en <nombre>.sitios.dev, con SSL gratis, sobre nuestra red global (330+ ciudades). Se conecta desde yapanel.yadominios.com/panel/cloud. Se empieza GRATIS y sin tarjeta: el plan Vista previa publica un sitio en <nombre>.sitios.dev para enseñárselo al cliente antes de cobrar nada; no incluye base de datos ni dominio propio, y eso llega al pasar a un plan de pago. Hay tres tipos de proyecto: (a) sitio estático, que solo necesita un index.html; (b) app ya compilada, con un _worker.js en la raíz; y (c) proyecto que se compila (Next.js, Astro, Vite), que NO se puede subir como código fuente: un GitHub Action lo compila y deja el resultado en la rama yapanel-build, y esa es la rama que se conecta. Dentro del código están disponibles env.DB (base de datos propia del sitio) y env.BUCKET (almacenamiento). La base se consulta por HTTP en POST yapanel.yadominios.com/api/hosting/db/query con el token de base de datos del panel. Cada push a la rama conectada republica solo. Esta página es la referencia técnica completa; una IA puede leerla y dejar una app publicada sin ayuda humana. Incluye el protocolo de entrega para asistentes de IA: al terminar el sitio hay que pasarle al humano, por chat y en un bloque copiable, la URL del repositorio y la rama, y después esperar el resultado (el enlace publicado o el error, que viene etiquetado como del repositorio o de la plataforma).
¿Tu página la hizo ChatGPT y ya está publicada allá? Entonces no necesitas esta guía para usar tu dominio: basta con agregar los registros DNS que ChatGPT te da. Está explicado en Cómo conectar un dominio a una página de ChatGPT Sites. Esta guía es para cuando quieres alojar el proyecto con nosotros.
Qué es (modelo mental en 20 segundos)
YaDominios Cloud es hosting serverless: conectas un repositorio público de GitHub desde el panel (yapanel.yadominios.com/panel/cloud), eliges un nombre, y el sitio queda en vivo en <nombre>.sitios.dev con HTTPS automático, en 330+ ciudades del mundo. No corremos tu build: desplegamos lo que hay en el repo. Tu repo debe traer el resultado final (HTML estático o un worker compilado). Cada git push a la rama conectada republica solo, en unos 5 minutos (ver «Cuánto tarda en verse un cambio»).
git push publica solo.Empieza gratis: publica primero, cobra después
No hace falta plan, ni dominio, ni tarjeta para publicar. El plan Vista previa es gratis y existe para una situación muy concreta del oficio: enseñarle la página al cliente antes de que pague. Publicas, le mandas el enlace por WhatsApp desde el mismo panel, y cuando él dice que sí, conectas su dominio y pasas a un plan de pago.
| Vista previa (gratis) | Planes de pago (desde $1.99/mes) | |
|---|---|---|
| Enlace en vivo con HTTPS | Sí, en <nombre>.sitios.dev | Sí |
| Sitios | 1 | De 1 a ilimitados según el plan |
Almacenamiento (env.BUCKET) | 512 MB | Desde 5 GB |
Base de datos (env.DB) | No | Sí |
| Tu dominio propio | No | Sí, con SSL |
Por eso, si tu proyecto necesita base de datos, tiene que estar en un plan de pago: en Vista previa env.DB no existe y el token de base de datos no se emite. Todo lo demás de esta guía funciona igual en los dos casos.
Si eres una IA y acabas de construir el sitio: cómo se entrega
Esta parte va dirigida al asistente que escribió el código (Claude, ChatGPT, Cursor, Lovable, el que sea). Tu trabajo no termina cuando el proyecto compila. Termina cuando la persona que te lo pidió tiene en la mano los dos datos que el panel le va a pedir, y sabe qué hacer con lo que le devuelvan. Casi nadie lo hace, y por eso el humano se queda mirando una pantalla sin saber qué pegar dónde.
Paso 1 — Sube el proyecto a GitHub, público
Repositorios privados: ya se pueden publicar. Hace falta que tu repositorio esté autorizado en la llave de lectura de YaDominios — escríbenos con el nombre del repositorio y lo habilitamos. Si el tuyo es público, no hay nada que hacer.
El repositorio puede ser público (lo bajamos sin pedirle credenciales a nadie) o privado ya autorizado. Sube el resultado, no el código sin compilar (mira «Los tres tipos de proyecto» más arriba): un index.html, un _worker.js ya empaquetado, o la rama que genere tu GitHub Action.
Paso 2 — Pásale al humano el repositorio y la rama, en un bloque para copiar
Son exactamente dos datos, ni uno más. No mandes un .zip, no le pidas que clone nada, no le pidas credenciales de Cloudflare (nunca hacen falta). Escríbeselo así, listo para copiar y pegar en yapanel.yadominios.com/panel/cloud:
Ya está el sitio en GitHub. Para publicarlo:
1. Entra a yapanel.yadominios.com/panel/cloud
2. Ponle un nombre corto (queda como nombre.sitios.dev)
3. Pega estos dos datos:
Repositorio: https://github.com/USUARIO/PROYECTO
Rama: main
4. Dale a «Publicar gratis»
Cuando termine, pásame el enlace que te salga —o el mensaje
en rojo, si sale alguno— y sigo desde ahí.
Si tu proyecto necesita compilarse, la rama no es main: es la que deja tu Action (por convención yapanel-build). Dilo claro en el mismo mensaje, porque es el error más común de todos.
Paso 3 — Quédate esperando el resultado. Van a volver con una de tres cosas
Publicar tarda hasta un minuto y el panel enseña seis pasos en vivo. Lo que te van a traer es una de estas tres, y cada una tiene una respuesta distinta:
| Lo que te pasan | Qué significa | Qué haces tú |
|---|---|---|
Un enlace nombre.sitios.dev | Está publicado y contestando. | Ábrelo, revisa que se vea bien, y avisa que quedó listo. |
| Un error con la etiqueta «Esto se arregla en tu repositorio» | El fallo es del proyecto, no de la plataforma. | Corrígelo, haz git push a la misma rama y avisa: no hay que volver a conectar nada, cada push republica solo. |
| Un error con la etiqueta «Esto es nuestro, no tuyo» | Falló la plataforma; el proyecto está bien. | No cambies el código. Que reintente en un minuto y, si sigue, que escriba a soporte. |
Los fallos que vas a ver, y qué corregir
| Mensaje | Qué pasó | Arreglo |
|---|---|---|
| «No se encontró … en la rama …» | El repositorio es privado, el nombre está mal o esa rama no existe. | Hazlo público o corrige la rama. |
| «Este repo es un proyecto que hay que compilar» | Subiste el código fuente (Next.js, Vite, Astro), no la página lista. | Sube la salida construida o configura la Action que deja la rama compilada. |
| «Falta index.html en la raíz» | No hay portada en ninguna de las carpetas que miramos. | Deja un index.html en la raíz o en dist/, build/, out/, public/, docs/. |
| «Cloudflare rechazó el paquete» | Tu _worker.js no arranca: no es módulo ES, o usa Durable Objects o Queues. | Empaquétalo como módulo ES con export default { fetch } y quita esas dependencias. |
Una regla que ahorra vueltas: si el panel dice que el fallo es nuestro, es nuestro. No te pongas a reescribir un proyecto que está bien — es la forma más rápida de romper algo que funcionaba.
Modo 1 — Sitio estático
Requisito único: un index.html. Lo buscamos en la raíz del repo o en public/, dist/, build/, site/, _site/, docs/ u out/ (la primera carpeta que lo tenga es la raíz publicada). Todos los archivos de esa carpeta se sirven como assets con caché de borde; el HTML se revalida siempre (max-age=0), así los cambios se ven al instante.
Lo que no se publica: todo lo que empieza por punto se queda fuera (.gitignore, .github/, .vscode/, .claude/). Son las notas del taller y no tienen por qué quedar colgadas en la página de tu cliente. La única excepción es .well-known/, que sí se publica porque ahí viven las verificaciones de dominio y las claves de indexación.
Modo 2 — App con backend (_worker.js)
Si la raíz publicada trae un archivo _worker.js, el sitio es una APP: ese archivo corre como un worker en el servidor de YaDominios Cloud y recibe TODAS las peticiones. Debe ser un solo archivo JavaScript ES-module ya compilado (haz bundle de tus dependencias con esbuild/rollup) con esta forma:
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
if (url.pathname.startsWith("/media/")) {
// tu backend aquí (env.DB, env.BUCKET)
return Response.json({ ok: true });
}
return env.ASSETS.fetch(request); // el resto: tus archivos estáticos
}
};
⚠️ No uses /api/ para tus rutas de backend. Los assets estáticos se sirven antes que tu worker; en apps que traen assets (Next.js/OpenNext) el prefijo /api/* puede quedar capturado por el enrutado de archivos y devolver 404 sin llegar a tu código. Usa otro prefijo (/media, /upload, /datos…). Es un detalle real de la plataforma, comprobado en producción.
Node.js: no necesitas configurar nada para usar APIs de Node (node:stream, node:crypto, etc.). Toda app con backend corre con Node compat activado automáticamente por YaDominios Cloud, con una fecha de compatibilidad reciente. Por eso los frameworks (Next.js con OpenNext, etc.) funcionan sin ajustes.
Al publicar una app, provisionamos automáticamente (idempotente, sin configurar nada):
| Binding | Qué es | Cómo se usa |
|---|---|---|
env.DB | Base de datos SQL propia del sitio (motor SQLite serverless). Se crea con nombre site-<nombre>-db. | await env.DB.prepare("SELECT * FROM t WHERE id=?").bind(1).all() |
env.BUCKET | Almacenamiento de archivos e imágenes propio del sitio (bucket site-<nombre>). | await env.BUCKET.put("foto.jpg", bytes) · await env.BUCKET.get("foto.jpg") |
env.ASSETS | Tus archivos estáticos del repo. | return env.ASSETS.fetch(request) |
| tus variables | Las variables de entorno que hayas guardado en el panel (incluidas las secretas). | env.STRIPE_KEY, env.API_URL… |
Nota sobre env.BUCKET: el binding y los permisos ya están en la plataforma. Si R2 aún no está activado en la cuenta al momento de publicar, la app sale igual (sin storage) y el bucket se conecta automáticamente en el siguiente deploy cuando se active. Programa contra env.BUCKET con normalidad.
Tablas: schema.sql
Si la raíz publicada trae schema.sql, lo ejecutamos contra la base del sitio en cada publicación. Escribe DDL idempotente:
CREATE TABLE IF NOT EXISTS clientes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
creado_en TEXT DEFAULT (datetime('now'))
);
_worker.js y schema.sql no se sirven al público: son código/config.
Los tres tipos de proyecto
Antes de publicar, ubica cuál es el tuyo. De esto depende todo lo demás.
| Tipo | Qué debe traer el repo | ¿Necesita compilación? |
|---|---|---|
| a) Sitio estático | index.html en la raíz o en dist/, build/, out/, public/, site/, _site/ o docs/ | No |
| b) App ya compilada | Un _worker.js en la raíz | No (ya la hiciste tú) |
| c) Proyecto que se compila Next.js, Astro, Vite, Nuxt… | El resultado de la compilación, en la rama yapanel-build | Sí |
⚠️ El caso (c) es donde se atasca todo el mundo: no se puede subir el código fuente y esperar que funcione. YaDominios Cloud no corre tu compilación: publica lo que hay en la rama conectada. Si subes el código fuente de un Next.js, no sale nada.
Proyectos que necesitan compilarse
La solución es un GitHub Action que compile solo y deje el resultado listo en una rama aparte llamada yapanel-build. En el panel conectas esa rama, no main.
main. El Action compila y publica en yapanel-build. El panel escucha esa rama.Next.js: la trampa del tamaño
La salida cruda del compilador NO se puede desplegar. Al compilar un Next.js con OpenNext, la carpeta .open-next queda con más de 1.000 archivos y unos 19 MB. Eso no se sube tal cual.
Hay que empaquetarla en un solo archivo antes de publicar. El GitHub Action que entregamos ya lo hace con wrangler. Si compilas a mano, ese paso de empaquetado no te lo puedes saltar: sin él, el despliegue falla.
El adaptador oficial es OpenNext (@opennextjs/cloudflare).
⚠️ Antes del Action: comprueba el par de versiones. Es la trampa que más caro sale
El adaptador no acepta cualquier versión de Next, y el rango que acepta DEJA UN HUECO dentro de la línea 16. No es un rango que solo suba por abajo: hay versiones de Next más nuevas que quedan fuera y versiones más viejas que entran.
Ejemplo real, la versión del adaptador de hoy:
@opennextjs/cloudflare 1.20.6 → next ">=15.5.24 <16 || >=16.3.3"
Next 15.5.24 … 15.x ✅ entra
Next 16.0.0 … 16.3.2 ❌ NO ENTRA ← el hueco
Next 16.3.3 en adelante ✅ entra
Y el hueco se mueve con cada versión del adaptador, así que no te aprendas los números: míralos en tu propio proyecto, que tarda un segundo.
node -p "require('./node_modules/@opennextjs/cloudflare/package.json').peerDependencies.next"
node -p "require('./node_modules/next/package.json').version"
Si tu Next cae en el hueco, el empaquetado falla con un error del compilador que no menciona las versiones — y te vas a pasar la tarde buscando el fallo en tu código, donde no está. Sube Next a una versión dentro del rango y listo. El Action de abajo ya trae la comprobación puesta: si no cuadran, se detiene y te dice exactamente qué versión tienes y cuál acepta el adaptador.
Ojo también con wrangler: el adaptador lo declara como dependencia par (hoy ^4.125.0). Instala el que pida.
Este es el Action completo:
# .github/workflows/build.yml
name: build-para-yadominios-cloud
on: { push: { branches: [main] } }
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npm ci
# EL PAR DE VERSIONES. El adaptador declara qué versiones de Next acepta,
# y ese rango DEJA UN HUECO dentro de la línea 16 que se mueve en cada
# publicación suya. Sin esta comprobación, una versión del hueco falla
# con un error del empaquetador que no dice la verdadera causa.
- run: |
RANGO=$(node -p "require('./node_modules/@opennextjs/cloudflare/package.json').peerDependencies.next")
MIA=$(node -p "require('./node_modules/next/package.json').version")
# Si no se pudo leer el rango, SE PARA. Un guardian que no sabe que
# comparar deja pasar todo, y eso es peor que no tenerlo.
[ -n "$RANGO" ] && [ -n "$MIA" ] || {
echo "::error::No se pudo leer la version de Next o el rango del adaptador."
exit 1
}
npx --yes semver -r "$RANGO" "$MIA" >/dev/null || {
echo "::error::Tu Next ($MIA) no lo acepta el adaptador, que exige: $RANGO"
echo "::error::Sube Next a una version dentro de ese rango y vuelve a intentar."
exit 1
}
echo "Next $MIA entra en el rango del adaptador ($RANGO)."
- run: npx opennextjs-cloudflare build
# IMPORTANTE: .open-next/worker.js NO es autónomo (importa ./cloudflare/,
# ./middleware/, etc.). Hay que empaquetarlo a UN solo archivo.
# Lo empaqueta WRANGLER, no esbuild directo: wrangler aplica las reglas
# correctas del runtime de Workers (node:*, condiciones workerd). Con
# esbuild a mano el paquete no compila o revienta al arrancar.
# --dry-run NO toca ninguna cuenta: solo escribe el archivo.
- run: |
npx wrangler deploy --dry-run --outdir=.dist-worker --minify
mkdir out-deploy
cp .dist-worker/worker.js out-deploy/_worker.js
cp -r .open-next/assets/* out-deploy/ 2>/dev/null || true
cp yadominios.json out-deploy/ 2>/dev/null || true
- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: yapanel-build
publish_dir: ./out-deploy
El paso de wrangler necesita dos cosas en tu repo: wrangler como devDependency, y un wrangler.jsonc en la raíz con al menos esto (el name da igual — con --dry-run nunca se despliega a Cloudflare):
// wrangler.jsonc
{
"name": "mi-sitio",
"main": ".open-next/worker.js",
"compatibility_date": "2026-07-01",
"compatibility_flags": ["nodejs_compat"],
"assets": { "directory": ".open-next/assets" }
}
Después de agregar el Action: haz un push a main, espera a que termine (pestaña «Actions» de tu repo), y comprueba que apareció la rama yapanel-build. Recién entonces conéctala en el panel.
Next.js con OpenNext: no tienes que hacer nada
OpenNext agrega por su cuenta tres clases de Durable Objects — DOQueueHandler, DOShardedTagCache y BucketCachePurge — aunque tu app no las use. YaDominios Cloud todavía no ofrece Durable Objects, y durante un tiempo eso hacía que un paquete perfectamente bueno no publicara.
Ya no: las quitamos nosotros al publicar, y te lo decimos en el paso «Paquete revisado» del registro. No hace falta que toques tu configuración ni que te escribas un limpiador.
Si quieres evitarlas desde el origen, en tu open-next.config.ts:
// open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
export default defineCloudflareConfig({
incrementalCache: undefined,
queue: undefined,
tagCache: undefined,
});
Aviso honesto: según la versión de OpenNext, esa configuración no siempre las saca del paquete — lo comprobamos con una integración real. Por eso la limpieza la hacemos nosotros y no dependemos de tu configuración. Para verlo por ti mismo:
grep -oE "DOQueueHandler|DOShardedTagCache|BucketCachePurge" .open-next/worker.js | sort -u
(La -E importa: sin ella, la barra vertical es un carácter literal y el comando responde «limpio» siempre, aunque las tres clases estén adentro.)
Lo que se pierde al no tenerlas: la revalidación en segundo plano (ISR). Las páginas se generan en la petición y se sirven desde la caché del borde — de sobra para una tienda o una web corporativa.
Si tu app usa Durable Objects PROPIOS (salas de chat, contadores en vivo, tiempo real), eso sí lo rechazamos y te lo decimos: esos no los podemos quitar sin romperte la app. Todavía no están disponibles.
Otros límites del modo app: tampoco hay colas. El worker final debe ser un único archivo ES-module cuyo export default tenga fetch; si tu compilador saca CommonJS (module.exports), pon el formato de salida en esm. El tamaño normal de un Next.js empaquetado (3–6 MB) no es problema.
Si algo falla, el panel te dice en qué paso
Publicar son seis pasos y los ves uno por uno, EN VIVO, en la pantalla del sitio: repositorio encontrado → rama descargada → paquete revisado → base de datos y almacenamiento listos → sitio publicado → comprobado en vivo. El último paso es la garantía: la plataforma VISITA tu página recién publicada y solo marca verde si contesta de verdad — "publicado" nunca significa "guardado pero inalcanzable". Si algo se cae, el paso que falló queda en rojo con el motivo exacto, y los siguientes en gris — no fallaron, ni llegaron a intentarse.
Para sitios sin servidor (blogs, landings), más simple: next build con output: "export" genera out/ con HTML estático — y out/ es una de las carpetas que detectamos.
Publicar y republicar
- Primera vez: panel → yapanel.yadominios.com/panel/cloud → nombre del sitio + URL del repo + rama → «Publicar mi sitio». Reglas del nombre: minúsculas, números y guiones, máx. 63, sin
--ni nombres reservados (www, api, admin, docs…). - Tu sitio queda vivo en
<nombre>.sitios.dev, con SSL, gratis y para siempre. - Después: cada
git pusha la rama conectada republica el sitio solo y limpia la caché, así que el cambio se ve al instante.
Caché de página completa: que los robots no te cuesten dinero
Si una página es igual para todos los visitantes, márcala y la plataforma la guarda. Las visitas siguientes —las de personas y, sobre todo, las de robots como GPTBot o el de Meta, que piden la misma página miles de veces al día— se sirven desde el borde sin despertar tu código ni tocar tu base de datos.
Basta una cabecera en la respuesta:
Cache-Control: public, s-maxage=300, stale-while-revalidate=3600
s-maxage=300: la copia vale 5 minutos. El techo es 1 hora, aunque pidas más.stale-while-revalidate=3600: pasado ese plazo, se sigue sirviendo la copia mientras se regenera por detrás. Nadie espera.- Cada vez que publicas, todas las copias se descartan: nunca se sirve la versión anterior de tu sitio.
Lo que nunca se guarda, para que no se mezclen datos entre personas: una visita que trae cookies o sesión (siempre recibe su página fresca), una respuesta que pone una cookie (Set-Cookie), una respuesta sin public, o con private / no-store. Por eso: no pongas cookies en páginas públicas (por ejemplo, la cookie de idioma de next-intl cuando el idioma ya va en la dirección) y nunca marques como públicos el carrito, la cuenta ni el pago.
Para comprobarlo, mira la cabecera x-yad-cache de la respuesta: HIT (servida desde la copia), STALE, MISS (se generó y se guardó) o BYPASS:<motivo> (no se guardó, y dice por qué: set-cookie, no-publica, sin-s-maxage…).
Cuánto tarda en verse un cambio (y por qué no es caché)
Hasta unos 5 minutos después de que el push llegue a la rama conectada. No es caché: tu sitio se sirve sin guardar copias (cache-control: no-store), y en cuanto la versión nueva se publica, se ve en <nombre>.sitios.dev y en tu dominio propio a la vez.
La espera viene de cómo nos enteramos del push: le preguntamos a GitHub cada 5 minutos si la punta de tu rama avanzó. Si avanzó, publicamos ahí mismo —la publicación en sí tarda unos 20 segundos— y queda anotado en tarjeta del sitio → «Registro de errores» como «Republicado solo: la rama avanzó a …», con la hora.
En un proyecto que se compila, súmale lo que tarde tu Action en compilar y empujar a yapanel-build: el reloj de los 5 minutos empieza cuando el Action termina, no cuando haces push a main.
Ejemplo real: push a yapanel-build a las 15:46:35, versión nueva en vivo a las 15:51:23. Si pasan más de 10 minutos y el registro no dice nada, ahí sí algo falla.
Solo republica la rama conectada (y es a propósito)
Los push a otras ramas —por ejemplo main en un proyecto que se compila— no republican. No es un descuido: el compilador tarda un par de minutos, así que si main republicara, se desplegaría la compilación anterior (la que ya estaba lista), no la del cambio que acabas de hacer. Verías tu cambio "publicado" y en realidad estarías viendo el de antes.
Por eso: en proyectos que se compilan, la rama conectada es yapanel-build, y esa la escribe el Action cuando ya terminó de compilar.
Si algo falla al publicar
El motivo queda escrito en el panel: tarjeta del sitio → «Registro de errores». Si te ayuda una IA, copia ese texto tal cual y pégaselo: trae la ruta, el método y la traza completa.
Y si una versión no logra publicarse, te lo decimos. Lo reintentamos por tu cuenta unas cuantas veces —un tropiezo pasajero de GitHub se arregla solo—, pero no damos vueltas en falso: al tercer intento paramos y te lo escribimos en el registro del sitio, en rojo. Tu web no se cae mientras tanto: sigue en línea con la última versión que sí publicó. Nosotros recibimos el aviso al mismo tiempo que tú.
Publicar y conectar el dominio son dos cosas distintas
No hace falta tener dominio para publicar. El orden natural es:
- Publicas → tu página ya está viva en
<nombre>.sitios.devy la puedes compartir. - Después, si quieres, le conectas tu dominio propio desde la tarjeta del sitio.
Son dos flujos independientes. El subdominio .sitios.dev nunca se apaga, aunque conectes un dominio propio.
API de base de datos (consola y migraciones)
Puedes consultar la base de tu sitio por HTTP, sin entrar al panel. Sirve para que una IA o un script creen tablas, siembren datos y hagan consultas.
1. Consigue tu token de base de datos
Ojo con «Regenerar token». Genera uno nuevo y el anterior deja de servir en el acto, sin vuelta atrás. Si tu sistema o la sesión de inteligencia artificial que te está ayudando están usando el token de ahora, se quedan sin acceso a la base hasta que les pases el nuevo — y eso, en mitad de un problema, es lo peor que puede pasar. Regenéralo solo si lo perdiste o crees que alguien más lo tiene.
Panel → YaDominios Cloud → tarjeta de tu sitio → botón «Ver token».
Se muestra UNA sola vez. Cópialo y guárdalo. Si lo pierdes, genera uno nuevo desde el mismo botón: el anterior deja de funcionar en ese momento.
Ese token abre solo la base de ESE sitio. No da acceso a ningún otro sitio ni a tu cuenta.
2. Haz la petición
POST https://yapanel.yadominios.com/api/hosting/db/query
Content-Type: application/json
{
"sitio": "nombre-del-sitio",
"token": "<tu token de base de datos>",
"sql": "select * from pedidos where id = ?",
"params": [1]
}
3. Respuesta
{
"results": [ { "id": 1, "total": 250 } ],
"rowsRead": 1,
"rowsWritten": 0
}
Reglas
- El SQL va siempre parametrizado: los
?dentro de"sql"y los valores en"params", en el mismo orden. Nunca pegues los valores dentro del texto del SQL: así se evitan las inyecciones. - Si tu consulta no lleva valores, manda
"params": []. - Para migraciones, manda tus
CREATE TABLE/ALTER TABLEen"sql".
Errores
| Código | Qué significa |
|---|---|
401 | El token no sirve: está equivocado, o este sitio todavía no tiene la consola activada. |
400 | Falta un campo del cuerpo, el sitio no existe, la base que pides no existe, o tu token fue REEMPLAZADO (ver abajo). |
500 | El SQL se ejecutó y falló. El mensaje viene en error. |
Lee siempre el campo error, no solo el código. Un token que se regeneró desde el panel devuelve 400, no 401 — porque no es un token inválido, es un token que ya fue válido — y el mensaje te lo dice con su fecha: «Este token fue REEMPLAZADO el … UTC desde el panel». Si tu programa solo trata el 401 como problema de credenciales, ese caso se te mezcla con los errores de consulta y vas a buscar el fallo en tu SQL, donde no está.
Y ahora lo puedes ver desde el panel. Cada llamada que le hagas a tu base por la API queda contada en YaDominios Cloud → tu sitio → «Registro de errores»: cuántas salieron bien, cuántas fallaron, y el último error completo con su motivo y el SQL que lo provocó. Es el primer sitio donde mirar cuando algo que llama a tu base «no hace nada».
Ejemplo completo (JavaScript)
const r = await fetch("https://yapanel.yadominios.com/api/hosting/db/query", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sitio: "mi-tienda",
token: process.env.YADOMINIOS_DB_TOKEN,
sql: "insert into pedidos (cliente, total) values (?, ?)",
params: ["Ana", 250]
})
});
const datos = await r.json();
console.log(datos.rowsWritten); // 1
Configuración de plataforma (wrangler.jsonc)
Pon siempre la compatibility_date junto a nodejs_compat: ese flag exige fecha 2024-09-23 o posterior, y sin ella el comportamiento queda al azar del valor por defecto de la plataforma. Para variables, KV, Durable Objects, colas, cron y compatibility flags, pon un yadominios.json en la raíz publicada (también aceptamos wrangler.jsonc, el formato que ya generan las IA). Leemos ese archivo y provisionamos/enlazamos todo automáticamente en YaDominios Cloud, aislado por sitio.
{
"compatibility_date": "2026-07-01",
"compatibility_flags": ["nodejs_compat"]
}
| Capacidad | Cómo se declara | Cómo se usa en tu código |
|---|---|---|
| Fecha de compatibilidad | compatibility_date en el archivo | La leemos y la aplicamos. Funciona. |
| Compatibility flags | compatibility_flags en el archivo | Los leemos y los aplicamos. Funciona. |
| Base de datos (SQLite) | Automática: cada sitio con plan de pago tiene la suya | env.DB. Funciona. |
| Almacenamiento de archivos | Automático, uno por sitio | env.BUCKET. Funciona. |
| Estáticos | Automático | env.ASSETS. Funciona. |
| Variables y secretos | En el panel → tu sitio → Variables de entorno. NO se leen del archivo | env.STRIPE_KEY. Funciona — pero solo las que pongas en el panel. |
| Correo saliente | Automático si tu sitio tiene dominio propio | env.EMAIL. Funciona. |
| KV (caché clave-valor) | — | Todavía no. Usa env.DB mientras tanto. |
| Colas | — | Todavía no. |
| Cron (tareas programadas) | — | Todavía no. Lee el aviso de abajo antes de diseñar nada alrededor de esto. |
| Durable Objects (estado en vivo, tiempo real) | — | Todavía no. Un paquete que exporte clases Durable Object se rechaza al publicar, con el motivo. |
Del archivo de configuración leemos hoy DOS cosas y solo dos: compatibility_date y compatibility_flags. Todo lo demás que pongas ahí —vars, kv_namespaces, queues, triggers, durable_objects— se ignora en silencio: publicamos igual y no verás ningún error. Ponlo si quieres, pero no cuentes con que haga nada.
Variables secretas: nunca las pongas en el repo. Van en el panel (se guardan cifradas del lado del servidor y se inyectan como secretos al desplegar; el panel solo muestra los nombres, nunca los valores). Al guardarlas, el sitio se re-publica para aplicarlas.
Cron (tareas programadas): todavía no existe, y esto hay que leerlo
YaDominios Cloud no ejecuta tareas programadas hoy. Nada de lo que declares las activa: ni triggers.crons en el archivo, ni un scheduled() exportado en tu _worker.js.
Y aquí está la trampa, dicha claro: si tu paquete exporta un scheduled(), la publicación funciona y no te avisa de nada. Parece que quedó puesto. No hay nada que lo dispare, nunca. Si tu tarea nocturna no corre, no es un fallo de tu código: es que esta pieza aún no está.
Qué hacer mientras tanto. Pon el reloj fuera y que llame a una ruta de tu sitio: un Cron Trigger de tu propia cuenta de Cloudflare, el planificador de tu servidor, o un servicio de cron por HTTP. Tu sitio se encarga del trabajo; el reloj solo lo despierta. Protege esa ruta con un secreto que pongas en las variables del panel, para que no la llame cualquiera.
Lo único que corre de nuestro lado con reloj es nuestro Vigilante, que hace un GET a la portada de tu sitio cada 5 minutos con el user-agent YaDominios-Vigilante/1.0 para comprobar que responde. No ejecuta nada tuyo ni toca tu base. Si ves esas visitas en tus registros, somos nosotros y es normal.
Dominio propio (minegocio.com)
Los planes Órbita en adelante incluyen dominio propio. Es autoservicio desde el panel: YaDominios Cloud → tu sitio → «Conectar mi dominio propio». Escribes tu dominio y el panel te muestra 2 nameservers únicos; los pegas en tu registrador (cada uno tiene su casilla para copiar) y en minutos u horas tu dominio sirve tu sitio con HTTPS automático. Tu subdominio nombre.sitios.dev sigue funcionando siempre.
Registro de errores (observabilidad)
En YaDominios Cloud → tu sitio → «Registro de errores» tienes tres cosas, y conviene saber qué contesta cada una:
- Lo que hizo la plataforma con tu sitio: cada publicación con su resultado, los cambios de token, los cortes por límite. Aquí se ve por qué un despliegue no subió.
- Las llamadas a tu base por la API: cuántas salieron bien y cuántas fallaron cada día, y el último error completo con su motivo y el SQL que lo provocó. Es lo que hay que mirar cuando un programa o un robot tuyo «llama y no pasa nada».
- Los errores de tu sitio: los últimos 20, con la hora, el método y la ruta. Si tu app lanza una excepción en producción, el visitante ve una página de error amable y aquí queda el error con su traza completa.
Si tu página la maneja una IA, copia el error tal cual y pégaselo: lleva la ruta, el método y la traza para arreglarlo.
Cómo comprobar que tu cambio llegó (léelo antes de dar un despliegue por roto)
No busques una frase exacta dentro del HTML. Los frameworks parten el texto entre elementos, así que una búsqueda literal falla aunque el cambio SÍ esté publicado.
Ejemplo real: quieres verificar que salió el texto «Tu lugar entre los 100». En el HTML publicado llega así:
<p>Tu lugar entre los <span>100</span></p>
Un grep "Tu lugar entre los 100" no devuelve nada, y concluirías que el despliegue falló. No falló: el texto está, partido en dos elementos.
Qué hacer en su lugar:
- Busca un fragmento corto y continuo que no cruce etiquetas (
"lugar entre los"). - O ábrelo en el navegador y míralo, que es lo definitivo.
- O compara la fecha de «última publicación» del panel con la hora de tu push.
Checklist para una IA que va a publicar aquí
- Identifica el tipo de proyecto (estático /
_worker.jsya compilado / requiere compilación). Si requiere compilación, no intentes subir el código fuente: no va a funcionar. - ¿Estático? → asegura
index.htmlen la raíz o endist/ build/ out/ public/ site/ _site/ docs/y haz push. - ¿App con backend ya compilada? →
_worker.jsen la raíz (bundle único,export default { fetch }), usaenv.DB/env.BUCKET/env.ASSETS, agregaschema.sqlsi necesitas tablas. - ¿Requiere compilación (Next.js, Astro, Vite…)? → agrega el GitHub Action, comprueba que se creó la rama
yapanel-build, y conecta esa rama en el panel. En Next.js el paso de empaquetado es obligatorio:.open-nextcruda (1000+ archivos, ~19 MB) no se despliega. - Conecta el repo en yapanel.yadominios.com/panel/cloud (una sola vez). Cada push a la rama conectada publica solo.
- ¿Datos? → saca el token de base de datos con «Ver token» y usa
POST https://yapanel.yadominios.com/api/hosting/db/querycon SQL parametrizado. - Al verificar, no busques frases literales en el HTML (ver arriba). Si algo falló, lee «Registro de errores» en la tarjeta del sitio.
Preguntas frecuentes
Corren mi npm run build?
No. Desplegamos lo que hay en el repo: HTML estático o un _worker.js ya compilado. El build se automatiza con un GitHub Action en tu propio repo.
Puedo usar Node.js puro (Express)?
No directamente: el backend corre como un worker (export default { fetch }). Express no aplica; usa el patrón worker o un framework con adaptador (Next.js vía OpenNext, Hono, etc.).
El repo debe ser publico?
Sí por ahora: conectamos repos públicos de GitHub. Los archivos se leen por la API de GitHub al publicar.
Que limites tiene la base de datos?
Es una base SQLite serverless: ideal para apps pequeñas y medianas. Cada sitio tiene su propia base aislada, con respaldo automático.
Como conecto mi dominio propio (midominio.com)?
Los planes Orbita en adelante incluyen dominio propio: se configura con nuestro equipo desde el panel. El subdominio nombre.sitios.dev queda siempre disponible.