YaDominiosYaDominios

Publishing on YaDominios Cloud: complete technical guide (for developers and AI)

Updated: 2026-07-18 · YaDominios

YaDominios Cloud publishes a GitHub repository as a live site at yourname.sitios.dev, on our global network (330+ cities). There are two modes: static site (an index.html in the repo) or app with a backend (a compiled _worker.js at the root, which receives a SQL database in env.DB, file storage in env.BUCKET, and assets in env.ASSETS). Every push to GitHub republishes the site automatically. This page is the complete technical reference; an AI can read it and leave an app ready with no human help.

What it is (mental model in 20 seconds)

YaDominios Cloud is serverless hosting: you connect a public GitHub repository from the dashboard (app.yadominios.com → YaDominios Cloud), pick a name, and the site goes live at <name>.sitios.dev with automatic HTTPS, in 330+ cities worldwide. We don't run your build: we deploy what's in the repo. Your repo must carry the final result (static HTML or a compiled worker). Every git push republishes on its own, in seconds.

Your repo GitHub git push YaDominios Cloud builds and publishes seconds yourname.sitios.dev live · HTTPS · global network
Connect once; after that every git push publishes on its own.

Mode 1 — Static site

Single requirement: an index.html. We look for it at the repo root or in public/, dist/, build/, site/, _site/, docs/, or out/ (the first folder that has it is the published root). Every file in that folder is served as an edge-cached asset; HTML is always revalidated (max-age=0), so changes show instantly.

Mode 2 — App with a backend (_worker.js)

If the published root carries a _worker.js file, the site is an APP: that file runs as a worker on the YaDominios Cloud server and receives ALL requests. It must be a single, already-compiled ES-module JavaScript file (bundle your dependencies with esbuild/rollup) with this shape:

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    if (url.pathname.startsWith("/media/")) {
      // your backend here (env.DB, env.BUCKET)
      return Response.json({ ok: true });
    }
    return env.ASSETS.fetch(request); // everything else: your static files
  }
};

⚠️ Don't use /api/ for your backend routes. Static files are served before your worker; in apps that ship assets (Next.js/OpenNext) the /api/* prefix can be captured by the file router and return 404 without reaching your code. Use another prefix (/media, /upload, /data…). It's a real platform detail, verified in production.

Node.js: you don't need to configure anything to use Node APIs (node:stream, node:crypto, etc.). Every app with a backend runs with Node compat enabled automatically by YaDominios Cloud, with a recent compatibility date. That's why frameworks (Next.js with OpenNext, etc.) work with no tweaks.

When you publish an app, we automatically provision (idempotent, zero setup):

BindingWhat it isHow to use it
env.DBThe site's own SQL database (serverless SQLite engine). Created as site-<name>-db.await env.DB.prepare("SELECT * FROM t WHERE id=?").bind(1).all()
env.BUCKETThe site's own file and image storage (bucket site-<name>).await env.BUCKET.put("photo.jpg", bytes) · await env.BUCKET.get("photo.jpg")
env.ASSETSYour static files from the repo.return env.ASSETS.fetch(request)
env.UPLOAD_TOKENPassword the cloud generates on its own to protect your upload route. View and copy it in the dashboard; don't invent it.if (req.headers.get("x-upload-token") !== env.UPLOAD_TOKEN) return new Response("401", { status: 401 })

Note on env.BUCKET: the binding and permissions are already on the platform. If R2 isn't enabled on the account at publish time, the app ships anyway (without storage) and the bucket connects automatically on the next deploy once it's enabled. Program against env.BUCKET as usual.

Tables: schema.sql

If the published root carries schema.sql, we run it against the site's database on every publish. Write idempotent DDL:

CREATE TABLE IF NOT EXISTS customers (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  created_at TEXT DEFAULT (datetime('now'))
);

_worker.js and schema.sql aren't served to the public: they're code/config.

Next.js and frameworks (SSR, server actions, dynamic routes)

A Next.js app DOES run on YaDominios Cloud, but you have to compile it to a Worker before pushing (we don't run next build). The official path is the OpenNext for Cloudflare adapter (@opennextjs/cloudflare), which turns the app into a worker + assets. Automate it with a GitHub Action that builds and leaves the result in the repo (or in a deploy branch you connect in the dashboard):

# .github/workflows/build.yml
name: build-for-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 && npx opennextjs-cloudflare build
      # IMPORTANT: .open-next/worker.js is NOT standalone (it imports ./cloudflare/,
      # ./middleware/, etc.). You must bundle it into ONE file:
      - run: |
          npx esbuild .open-next/worker.js --bundle --format=esm             --platform=neutral --conditions=workerd,worker,browser             --external:cloudflare:workers --outfile=_worker_bundle.js
          mkdir out-deploy
          mv _worker_bundle.js out-deploy/_worker.js
          cp -r .open-next/assets/* out-deploy/ 2>/dev/null || true
      - uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_branch: deploy
          publish_dir: ./out-deploy

Current app-mode limits: the platform does NOT yet support Durable Objects or queues. Configure OpenNext without a revalidation queue (ISR off or simple asset caching) so the bundled worker doesn't depend on those exports. The final worker must be a single ES-module file whose default export has fetch.

For serverless-free sites (blogs, landings), simpler: next build with output: "export" generates out/ with static HTML — and out/ is one of the folders we detect.

Publish and republish

  1. First time: dashboard → app.yadominios.com → Services → YaDominios Cloud → site name + repo URL → “Publish my site.” Name rules: lowercase, numbers and hyphens, max 63, no -- and no reserved names (www, api, admin, docs…).
  2. After that: every git push to the connected branch republishes the site automatically (GitHub webhook). There is no step 2.

Database API (console and migrations)

Every site with a database can be queried over HTTP with a single-site token generated in the dashboard (Cloud → your site → “Open database”). The token only grants access to THAT site's database, expires, and lets an AI or script run queries and migrations:

POST https://hooks.sitios.dev/db/query
Content-Type: application/json

{ "token": "<dashboard token>", "sql": "SELECT * FROM customers LIMIT 10", "params": [] }

→ { "ok": true, "site": "mysite", "results": [ … ], "meta": { … } }

For migrations, send your CREATE TABLE/ALTER TABLE in sql (one statement or several separated by “;”). Errors return { "ok": false, "error": "…" } with HTTP 4xx.

Platform configuration (yadominios.json)

For variables, KV, Durable Objects, queues, cron, and compatibility flags, add a yadominios.json at the published root (we also accept wrangler.jsonc, the format AIs already generate). We read that file and provision/wire everything automatically on YaDominios Cloud, isolated per site.

{
  "compatibility_flags": ["nodejs_compat"],
  "vars": { "API_URL": "https://api.yourservice.com" },
  "kv_namespaces": [{ "binding": "CACHE" }],
  "durable_objects": { "bindings": [{ "name": "ROOM", "class_name": "Room" }] },
  "migrations": [{ "new_sqlite_classes": ["Room"] }],
  "queues": { "producers": [{ "binding": "QUEUE", "queue": "jobs" }] },
  "triggers": { "crons": ["*/10 * * * *"] }
}
CapabilityHow you declare itHow you use it in your code
Public variablesvars in the file (they live in the repo)env.API_URL
SECRET variables (API keys)In the dashboard → your site → Environment variables (NOT in the repo)env.STRIPE_KEY
KV (cache/key-value)kv_namespacesawait env.CACHE.get("k")
Durable Objects (state, real time)durable_objects + migrations (use new_sqlite_classes)env.ROOM.get(env.ROOM.idFromName("x"))
Queuesqueues.producers (requires Queues enabled on the account)await env.QUEUE.send(msg)
Crontriggers.cronsYour worker responds to GET /__scheduled (we invoke it on your cron)
Compatibility flagscompatibility_flags

Secret variables: never put them in the repo. They go in the dashboard (stored encrypted server-side and injected as secrets at deploy; the dashboard shows only the names, never the values). When you save them, the site is re-published to apply them.

Cron (scheduled tasks): declare the expression in triggers.crons and expose a GET /__scheduled route in your worker with your task. Our scheduler invokes it at the right minute (it arrives with the x-yad-cron header). With OpenNext/Next, add that route as one more endpoint in your worker.

Custom domain (yourbusiness.com)

Órbita plans and up include a custom domain. It's self-service from the dashboard: YaDominios Cloud → your site → “Connect my own domain.” You type your domain and the dashboard shows you 2 unique nameservers; you paste them at your registrar (each has its own copy box) and within minutes to hours your domain serves your site with automatic HTTPS. Your name.sitios.dev subdomain keeps working forever.

Error log (observability)

If your app throws an exception in production, the visitor sees a friendly error page and the error is recorded with its full stack under YaDominios Cloud → your site → “Error log” (last 20). If an AI runs your site, copy the error verbatim and paste it in: it has the path, the method, and the trace to fix it.

Checklist for an AI publishing here

  1. Is the app static? → make sure index.html is at the root (or out/ with a static export) and push.
  2. Does it have a backend? → produce a compiled _worker.js (single bundle, export default { fetch }), use env.DB/env.BUCKET/env.ASSETS, add schema.sql, and push.
  3. Next.js with SSR? → OpenNext adapter + the Action above; connect the deploy branch in the dashboard.
  4. Connect the repo at app.yadominios.com (once). Every push after that publishes on its own.
  5. Data? → use the dashboard token against POST /db/query to create tables, seed, and query.

Frequently asked questions

Do you run my npm run build?

No. We deploy what's in the repo: static HTML or an already-compiled _worker.js. The build is automated with a GitHub Action in your own repo.

Can I use plain Node.js (Express)?

Not directly: the backend runs as a worker (export default { fetch }). Express doesn't apply; use the worker pattern or a framework with an adapter (Next.js via OpenNext, Hono, etc.).

Does the repo have to be public?

Yes for now: we connect public GitHub repositories. The files are read via the GitHub API on publish.

What are the database limits?

It's a serverless SQLite database: ideal for small and medium apps. Each site has its own isolated database, with automatic backup.

How do I connect my own domain (mydomain.com)?

Órbita plans and up include a custom domain: it's self-service from the dashboard (your site → Connect my own domain). The name.sitios.dev subdomain stays available forever.

Keep reading

Ready for your domain?

Search for it now and have it live in minutes.

Search my domain