# HostEdge documentation > Hosting for static sites and Workers apps: deploy from a folder, a GitHub repo or your AI assistant, and get a URL. Built-in analytics with revenue, databases, file storage, cron jobs, forms, uptime monitoring, status pages and password protection. Index: https://hostedge.app/llms.txt --- Source: https://hostedge.app/docs Markdown: https://hostedge.app/docs.md # Getting started HostEdge is hosting built for AI agents: ask your assistant to deploy static sites and Workers apps, or do it yourself. Every deployment gets its own URL, production lives at `.hostedge.app`, and custom domains get HTTPS automatically. ## Deploy in about a minute Pick whichever is closest to what you have: 1. **Your AI assistant.** Connect it over MCP, add the [Agent kit](https://hostedge.app/docs/agent-kit) so it knows how HostEdge works, and ask it to deploy. It uploads the files, reads the logs and can roll back. See [AI assistants](https://hostedge.app/docs/ai-assistants). 2. **A GitHub repository.** Choose **Import from GitHub**, install the HostEdge app on the account that owns the repository, and pick it. Every push to the production branch deploys; every other branch gets a preview. See [GitHub](https://hostedge.app/docs/github). 3. **The CLI.** `npx hostedge login` then `npx hostedge deploy` in your project. See [CLI](https://hostedge.app/docs/cli). 4. **A template.** Static HTML, a waitlist page, Astro, Next.js (static export), Eleventy, Vite (plain, React, Vue or Svelte), a Hono API and an API with a database deploy in one click, which shows the pipeline end to end. 5. **The dashboard.** Choose **Deploy a site** and drop your files (or a `.zip`) onto the page. HostEdge detects the framework, uploads only the files it doesn't have yet, and streams the build log. ## What you get with every project - A production URL, `https://.hostedge.app`, that always points at the current production deployment. - An immutable URL per deployment, `https://--.hostedge.app`, so you can open any old version. - A preview URL per branch, `https://--git-.hostedge.app`, that follows the branch's latest deployment. - Build and runtime logs, request analytics, encrypted environment variables and up to 100 custom domains depending on your plan. ## Next steps - [How deployments work](https://hostedge.app/docs/deployments): statuses, previews, redeploys and rollbacks. - [Custom domains](https://hostedge.app/docs/domains): the exact DNS records to add. - [Environment variables](https://hostedge.app/docs/environment-variables): secrets per environment. --- Source: https://hostedge.app/docs/deployments Markdown: https://hostedge.app/docs/deployments.md # Deployments A deployment is one immutable version of your site. HostEdge never changes a deployment after it is built; going live, rolling back and promoting a preview only move routes. ## Statuses | Status | Meaning | | --------- | ------------------------------------------------------------------------------------ | | Queued | Waiting for a builder. Usually a second or two. | | Building | Installing dependencies and running your build command (skipped for static uploads). | | Deploying | Uploading assets and the Worker script to the edge. | | Ready | Live at its own URL, and at the production URL if it is a production deployment. | | Failed | Something went wrong. The log says what, in plain words, and what to change. | | Canceled | You stopped it before it finished. | New free accounts' deployments can also show **In review**: the files are uploaded but not reachable until a person checks them. See [Limits and fair use](https://hostedge.app/docs/limits#first-deploy-checks). ## Uploads Uploads are content-addressed. Each file is hashed in your browser (or by the CLI), HostEdge answers with the hashes it hasn't seen in your workspace, and only those are sent. Re-deploying a site where one file changed uploads one file. HostEdge refuses symbolic links, paths that escape the folder, and files that look like secrets (`.env`, private keys). `.git`, `node_modules` and other tool folders are skipped. ## Builds If the project has a build command, it runs in an isolated container with your environment variables for that environment. The output folder (for example `dist`) is what gets deployed. Without a build command the uploaded files are deployed as they are. ## When a deployment fails A failed deployment shows **What went wrong** above the build log: a short title, the likely cause, numbered fixes in order of likelihood and the settings to check, with links to them. It reads the failure reason and the end of the log, so it covers the usual suspects: a missing package, an out-of-date lockfile, an output directory that does not match your build, a Node.js or memory problem, TypeScript or lint errors, missing environment variables, plan limits, server code that is too large or uses Node.js APIs Workers do not have, timeouts and registry errors. **Copy a prompt for your AI assistant** puts the diagnosis and the relevant log lines (secrets removed) on your clipboard, ready to paste. Assistants and scripts can read the same thing with `GET /api/v1/deployments/:id/explain`. When the failure is not one HostEdge recognises, the panel quotes the last error lines instead and says so. Start from the first error in the log, not the last. ## Previews Deployments from branches other than the production branch are previews. They never touch production. Each branch has a moving URL that follows its latest preview, and pull requests get a comment with the link. ## Redeploy, roll back, promote - **Redeploy** builds the same source again (useful after changing environment variables). - **Roll back** points production at an earlier ready deployment instantly. No rebuild. You can undo it the same way. - **Promote** makes a preview the production deployment. ## Cancel Queued and building deployments can be canceled from the deployment page or the list. --- Source: https://hostedge.app/docs/frameworks Markdown: https://hostedge.app/docs/frameworks.md # Frameworks HostEdge deploys a folder of static files, plus optional server code that runs as a Worker on a global edge network. **Any framework that can build to static files works, and Next.js, Astro, SvelteKit, Nuxt and React Router can render on the server too.** The presets below only fill in the commands and the output folder; you can change them at any time in **Project › Settings**. HostEdge looks at your `package.json` (and your lockfile) when you upload or import a project and picks the most specific match, so a Nuxt project is detected as Nuxt rather than Vite. ## Static sites | Framework | Detected when | Build command | Output | | ----------- | -------------------------------- | -------------------- | ----------------- | | Static HTML | An `index.html`, no build script | none | the folder itself | | Astro | `astro` | `npm run build` | `dist` | | Gatsby | `gatsby` | `npm run build` | `public` | | Eleventy | `@11ty/eleventy` | `npx @11ty/eleventy` | `_site` | ## Apps | Framework | Detected when | Build command | Output | | --------------------------- | ----------------------------- | ------------------- | --------------------- | | Next.js (static export) | `next` | `npm run build` | `out` | | Nuxt (static) | `nuxt` | `npx nuxi generate` | `.output/public` | | SvelteKit (static) | `@sveltejs/kit` | `npm run build` | `build` | | React Router (SPA mode) | `@react-router/dev` | `npm run build` | `build/client` | | Vite + React, Vue or Svelte | `vite` and the UI library | `npm run build` | `dist` | | Vite | `vite` (Solid, Preact, Lit …) | `npm run build` | `dist` | | Angular | `@angular/core` | `npm run build` | `dist//browser` | | Create React App | `react-scripts` | `npm run build` | `build` | Single-page apps (Vite, Angular, Create React App, React Router) are served with SPA fallback: unknown paths return `index.html` so client-side routing works. Everything else returns your `404.html` if you have one. ## Documentation | Framework | Detected when | Build command | Output | | ---------- | ------------------ | -------------------------------------- | -------------------------- | | Docusaurus | `@docusaurus/core` | `npm run build` | `build` | | VitePress | `vitepress` | the script that runs `vitepress build` | `/.vitepress/dist` | ## Server-rendered apps | Framework | Detected when | Build command | Output | | --------------------- | ------------------------------------------------- | ------------------------------------------- | ------------------------ | | Next.js (full) | `next` | `npx opennextjs-cloudflare build` | `.open-next/assets` | | Astro (server) | `astro` and `@astrojs/cloudflare` | `npm run build` | `dist/client` | | SvelteKit (server) | `@sveltejs/kit` and `adapter-cloudflare` | `npm run build` | `.svelte-kit/cloudflare` | | Nuxt (server) | `nuxt` and `nitro-cloudflare-dev` or `wrangler` | `npx nuxi build --preset=cloudflare_module` | `.output/public` | | React Router (server) | `@react-router/dev` and `@cloudflare/vite-plugin` | `npm run build` | `build/client` | Each framework's edge adapter writes the server code; after your build command, HostEdge bundles it into a Worker (with `wrangler deploy --dry-run`, using your `wrangler.jsonc` if the project has one) and serves your static files next to it. Pages, API routes, server actions, middleware, loaders and form actions all work. Prerendered pages are served as files without waking the server. Things to know: - **Next.js** works without setup. If the project has no `@opennextjs/cloudflare`, `open-next.config.ts` or `wrangler.jsonc`, the build adds them (your own files always win). For a static export (`output: "export"`), pick **Next.js (static export)** instead. - **Next.js caching (ISR) is on automatically.** The first deploy creates a page cache and a tag database for the project (shown in **Storage**, free and not counted against your plan). Pages prerendered at build time are in the cache before the deploy goes live. Pages with `revalidate` are served instantly and refreshed in the background once stale; `revalidatePath` and `revalidateTag` work across all visitors. If you bring your own `open-next.config.ts`, use the object-storage incremental cache and the database tag cache to get the same behaviour. - **Node.js APIs** are available (`nodejs_compat`): `Buffer`, `AsyncLocalStorage`, `crypto` and most of `node:*`. Native modules and child processes are not. - **Bindings** from your own wrangler config are not used. Databases, key-value stores and file storage you create in **Project › Storage** are bound by name, and environment variables are available as usual. - **Size**: the server bundle must stay under 10 MB gzipped. The build log shows how many modules were bundled. ## Workers | Framework | Detected when | Build command | Output | | --------- | ------------- | --------------- | ------------------------------ | | Hono | `hono` | `npm run build` | `dist`, with `dist/_worker.js` | A `_worker.js` file at the top of the output folder becomes the Worker. For several modules, write a `_worker.js/` folder with an `index.js` entry (the usual Pages-style layout); `.js`, `.mjs`, `.cjs`, `.wasm`, `.txt`, `.html`, `.sql` and `.bin` files in it are uploaded as modules and never served as files. Static files are served alongside through the `ASSETS` binding. Workers run with the per-plan CPU and subrequest limits listed on [Pricing](https://hostedge.app/pricing), and outbound requests to private networks and cloud metadata endpoints are blocked. ## Anything else Pick **Other** and set the build command and output folder yourself. If your tool writes HTML, CSS and JavaScript to a folder, HostEdge can host it. ## Package managers HostEdge installs with the package manager your lockfile names: `npm ci` for `package-lock.json`, `pnpm install --frozen-lockfile` for `pnpm-lock.yaml`, and `yarn install --frozen-lockfile` (or `--immutable` for Yarn 2+) for `yarn.lock`. Without a lockfile it follows the `packageManager` field in `package.json`, then falls back to `npm install`. Builds run on Node.js 22. Bun projects build with npm. ## Root directory For monorepos, set the root directory to the folder that contains the app's `package.json`. Commands run there and the output folder is relative to it. A lockfile at the repository root is still used. --- Source: https://hostedge.app/docs/github Markdown: https://hostedge.app/docs/github.md # GitHub ## Connect On **New project**, choose **Connect GitHub**. You are sent to GitHub to install the HostEdge app on your account or organization and pick which repositories it can read. HostEdge asks only for what it uses: repository contents (read), metadata (read), commit statuses (write) and pull requests (write, for the preview comment). ## Import a repository Pick a repository from the list. HostEdge detects the framework from the default branch and deploys it. The default branch becomes the production branch; change it in **Project › Settings**. ## Connect a project you already deployed Deployed from a folder, the CLI or a template first? Open **Project › Settings › Git repository** and choose **Connect repository**. Pick the repository and, if you like, a production branch (the default branch otherwise). From then on, pushes to that branch deploy to this same project and other branches get previews. The project keeps its URL, domains, analytics and history. Connecting does not deploy anything by default, so the live site stays as it is until the next push. Turn on **Deploy this branch now** to publish the branch immediately instead. You can still deploy from a folder or the CLI afterwards, and **Disconnect** unlinks the repository again. If you have not connected GitHub yet, the dialog sends you to GitHub to install the HostEdge app first; come back to the project's settings afterwards to finish. ## Push to deploy - A push to the production branch creates a production deployment. - A push to any other branch creates a preview with its own moving URL. - Deleting a branch removes its moving preview URL. Each deployment's own URL keeps working. ## Commit statuses and pull requests Each commit gets a `HostEdge` (or `HostEdge Preview`) status that links to the deployment while it builds and to the site when it's ready. Pull requests get one comment with the preview link, updated on every push. ## Disconnect Remove the HostEdge app from the repository in GitHub's settings. Existing deployments stay online. --- Source: https://hostedge.app/docs/deploy-button Markdown: https://hostedge.app/docs/deploy-button.md # Deploy button Ship a template, a starter or an open-source tool? Put this in your README and anyone can run their own copy on HostEdge: ![Deploy to HostEdge](https://hostedge.app/button.svg) ```markdown [![Deploy to HostEdge](https://hostedge.app/button.svg)](https://hostedge.app/new?repo=github.com/OWNER/REPO) ``` ## How it works 1. The visitor signs in (or creates an account) and lands on a short page that names your repository. 2. They pick a project name and a workspace, and press **Deploy**. 3. HostEdge downloads the repository, detects the framework, builds it and gives them a live URL. The repository must be public. It is copied once: later pushes to your repository do not change their project. They can connect their own fork from GitHub at any time to get push-to-deploy. ## Options | Parameter | Example | Meaning | | --------- | ----------------------------------- | --------------------------------------------------------------------------------------- | | `repo` | `github.com/acme/app/tree/main/web` | The repository; add `/tree//` for a branch or a subfolder of a monorepo | | `name` | `my-waitlist` | Suggested project name | ## Environment variables If the repository has a `.env.example`, HostEdge lists its variable names after the first deploy so the visitor knows what to set. `.env` files and other files that look like secrets are never copied. ## Without a button The **New project** page has a field for any public repository link, so you can deploy something you found on GitHub without connecting your account. --- Source: https://hostedge.app/docs/domains Markdown: https://hostedge.app/docs/domains.md # Custom domains ## Add a domain In **Project › Domains**, enter the domain (`shop.example.com` or `example.com`). HostEdge shows the exact records to create at your DNS provider, with copy buttons. ## Records For a subdomain such as `shop.example.com`: | Type | Name | Value | | ----- | ------ | -------------------- | | CNAME | `shop` | `cname.hostedge.app` | For an apex domain such as `example.com`, use your provider's CNAME flattening (sometimes called ALIAS or ANAME) with the value `cname.hostedge.app`. HostEdge also shows a TXT record when your provider needs ownership verification before the certificate is issued. ## Verification and HTTPS HostEdge checks DNS automatically every few minutes and when you press **Check now**. When it fails, the page tells you what DNS currently returns next to what it needs, for example _“found A 192.0.2.1, expected CNAME cname.hostedge.app”_. Certificates are issued and renewed automatically once DNS is right. Domains that don't verify within 7 days are marked failed; fix the record and check again. ## www and apex When you add `example.com`, HostEdge offers to add `www.example.com` as a redirect (and the other way round). Redirect aliases don't count toward your plan's domain limit. ## Primary domain The primary domain is where redirects point and the link shown on the project. Make any active domain primary from its menu. ## Remove Removing a domain stops serving it immediately. Delete the DNS record afterwards. --- Source: https://hostedge.app/docs/environment-variables Markdown: https://hostedge.app/docs/environment-variables.md # Environment variables ## Environments Every variable belongs to one or more environments: - **Production**: production deployments. - **Preview**: branch and pull-request deployments. - **Development**: what `hostedge env pull` writes to `.env.local` for local work. ## Adding variables Add them one by one or paste a whole `.env` file: quotes, `export` prefixes, comments, escapes and multi-line values are understood, and any line that can't be read is pointed out by number. ## How they're stored Values are encrypted with AES-256-GCM before they reach the database, bound to the project, name and environment so a value can't be moved to another variable. The list shows names only. Revealing a value is a deliberate click, available to Developers and above, and recorded in the audit log. ## Using them Variables are available to your build command and, for Workers projects, at runtime as `env.NAME`. Static sites only see them at build time. ## Changes need a redeploy Deployments keep the values they were built with. After a change, HostEdge offers to redeploy production with the new values. ## Limits Up to 63 variables per project and 5 KB per value (platform limits). Names starting with `HOSTEDGE_` or `CF_` are reserved. Every deployment also receives `HOSTEDGE_PROJECT_ID`, `HOSTEDGE_MAIL_URL` and `HOSTEDGE_MAIL_SECRET` (used by [Authentication](https://hostedge.app/docs/authentication) to send sign-in emails) and `HOSTEDGE_CRON_SECRET` (used by [Cron jobs](https://hostedge.app/docs/cron-jobs)). Treat them like any secret. --- Source: https://hostedge.app/docs/protection Markdown: https://hostedge.app/docs/protection.md # Protection, redirects and spend safety Everything on this page is in **Project › Settings › Protection** and **Redirects & headers**, needs the Developer role or above, and is enforced at the edge before your code runs. Changes apply within seconds. ## Password protection Set a password and choose what it covers: - **Preview and deployment URLs**: production and your custom domains stay public. Every deployment's own URL and every branch preview asks for the password. Good for work in progress. - **Everything, production too**: for private betas, staging sites and client work. Visitors see a short password page and stay signed in for 30 days on that browser. Changing the password signs everyone out. Passwords are stored as PBKDF2 hashes. ## Share links Create a link for a client or a tester: it opens a protected (or paused) site without the password, and can expire after 1, 7 or 30 days. The link is shown once; revoke it whenever you like. It works on production and on any preview: add `?hostedge_share=…` to the address. ## Maintenance mode Turn it on and visitors see a "Back soon" page with your message (status 503, so search engines come back later). You can still get in with the site password or a share link. ## AI crawlers **Block AI crawlers** refuses crawlers that collect training data, such as GPTBot, ClaudeBot, CCBot, PerplexityBot, Bytespider and Amazonbot. Search engines are not affected. ## Daily request cap Protect your plan's allowance from a traffic spike or a scraper. Set the number of requests a project may serve per UTC day; past it, the site shows a "paused for today" page until midnight UTC and admins are told once. Raising or removing the cap brings it back. The cap is checked every few minutes, so a site can go slightly over it. ## Redirects Rules run in order before your code: | From | To | Result | | ----------- | --------------------------------- | ---------------------------------------- | | `/old-page` | `/new-page` | One page | | `/blog/*` | `/posts/:splat` | `/blog/2026/hello` → `/posts/2026/hello` | | `/docs/*` | `https://docs.example.com/:splat` | To another site | Choose 301 or 308 for permanent moves, 302 or 307 for temporary ones (307 and 308 keep the request method). The query string is kept unless the destination has its own. Up to 100 redirects. ## Response headers Add headers to matching responses, for example `Cache-Control: public, max-age=31536000, immutable` on `/assets/*`, or `X-Robots-Tag: noindex` on `/*` for a staging site. Headers that would break responses or sessions (`Set-Cookie`, `Content-Length`, `Content-Encoding`…) cannot be set. Up to 50 headers. --- Source: https://hostedge.app/docs/monitoring Markdown: https://hostedge.app/docs/monitoring.md # Uptime, errors and status pages Everything here lives in **Project › Monitoring**, and alerts are set up once per workspace in **Settings › Alerts**. ## Uptime monitors Click **Monitor <your URL>** and HostEdge checks your production URL every few minutes, starting right away. **Add monitor** checks any other address: an API, a health endpoint, a third-party service you depend on. A check passes when the URL answers with a status below 400 within 10 seconds (and, if you set one, the page contains your keyword). After **two failed checks in a row** the monitor is down: an incident opens and your alert channels hear about it. The first passing check resolves the incident and sends a "back up" alert with how long it was down. On the Starter plan and up, turn on **Check from 3 regions** (when adding a monitor, or from its menu). Each check then runs from North America, Europe and Asia-Pacific, and a check fails only when most regions fail, so a network problem in one region is not reported as an outage. Failed checks list how each region did. Each monitor shows uptime for 24 hours, 7 and 30 days, the average response time, a response-time chart for the last day, 90 days of daily bars and the recent failed checks. | Plan | Monitors per project | Checked as often as every | | ------- | -------------------- | ------------------------- | | Free | 2 | 5 minutes | | Starter | 10 | 1 minute | | Pro | 50 | 1 minute | | Agency | 100 | 1 minute | ## Errors Exceptions thrown by your Worker and `console.error` lines are grouped by their message, with numbers, IDs, quoted values and URLs ignored, so `User 42 not found` and `User 7 not found` are one error. Each group shows how often it happened, when it was first and last seen, and the last path. **Stack trace and request** opens the stack frames of the latest occurrence (when the runtime reports them), the request it happened in (method, path, status, country) and the deployment. **Resolve** an error once it is fixed: if it happens again, it reopens and you get an alert, because a regression is worth knowing about. **Ignore** keeps an error out of your way and out of your alerts. **Logs** opens the matching log lines. ## Status page In **Monitoring › Status page**, publish a page at `https://hostedge.app/status/` that shows your monitors with 90 days of uptime, current incidents and past ones. Share it with your users, or link it from your site's footer. To serve it from your own address, enter a domain such as `status.example.com` under **Custom domain** once the page is published, and create the CNAME record shown. The page goes live there when the domain verifies; it counts as one of your plan's custom domains and appears on the Domains page with a **Status page** badge. Monitors open and resolve incidents on their own. You can also **Report an incident** by hand (for example, a slow payment provider) and post updates as it moves from _Investigating_ to _Identified_, _Monitoring_ and _Resolved_. ## Alerts Add channels in **Settings › Alerts** (admins and owners): - **Email**: any address. - **Slack**: an incoming webhook URL (Slack › Apps › Incoming Webhooks). - **Discord**: a channel webhook URL (Channel settings › Integrations › Webhooks). - **Telegram**: a bot token from @BotFather and the chat ID. - **SMS** (Starter plan and up): a phone number in international format. HostEdge texts it a 6-digit code; alerts go to it once you enter the code. Up to 50 texts a day per workspace. Pick the events each channel gets: a monitor goes down or comes back, a new or returning error, a cron job failing three times in a row, a failed deployment. A channel can cover every project or only some. **Send test** checks the connection; if a delivery fails, the channel shows the last error. Webhook URLs, bot tokens and phone numbers are stored encrypted and never shown again. ### Escalation and quiet hours Each channel can wait before it gets "monitor down": **If still down after 5, 15, 30 or 60 minutes**. Use it to escalate, for example Slack right away and SMS only when an outage lasts. A delayed channel hears about each outage once, and gets "back up" only if it heard the site was down. **Quiet hours** (from, to, time zone) hold every alert except "monitor down" during those hours, so a new error at 3 a.m. waits in the dashboard while an outage still wakes you up. --- Source: https://hostedge.app/docs/storage Markdown: https://hostedge.app/docs/storage.md # Databases and storage Open **Project › Storage** and choose **Add storage**. Pick what you need, keep the suggested name, and HostEdge creates it in a few seconds. Your next deployment can use it as `env.`; there are no connection strings or keys to copy. | Type | Built on | Use it for | | --------------- | -------------- | --------------------------------------------------- | | SQL database | SQLite | Users, orders, anything with rows and queries | | Key-value store | Workers KV | Settings, feature flags, sessions, cached responses | | File storage | Object storage | User uploads, images, exports. No download fees | Each project gets its own resources. By default previews and production share them; give previews their own copy (below) to keep test data apart. ## Connect it to your code Storage reaches the code that runs on HostEdge: a Worker, or the server side of Astro, SvelteKit, Nuxt, Remix or Next.js. A static site has no server code to use it. After you add storage, the dashboard shows **Redeploy to connect env.DB** until a deployment includes it. ```js // SQL database (binding DB) const { results } = await env.DB.prepare('SELECT * FROM users WHERE email = ?').bind(email).all() await env.DB.prepare('INSERT INTO users (email) VALUES (?)').bind(email).run() // Key-value store (binding CACHE) await env.CACHE.put('flag:beta', 'on', { expirationTtl: 3600 }) const beta = await env.CACHE.get('flag:beta') // File storage (binding FILES) await env.FILES.put(`avatars/${userId}.png`, request.body) const file = await env.FILES.get(`avatars/${userId}.png`) ``` Binding names use capital letters, numbers and underscores. They cannot clash with an environment variable of the same project. ## Browse and edit data Developers, admins and owners can work with the data from the dashboard. Viewers see which storage exists, not what is in it. - **SQL console.** Run any SQL, one statement or several separated by semicolons. Click a table to see its rows. Results show the first 500 rows of each statement. Press Ctrl + Enter to run. The download icon next to a table saves it as CSV, and **Download .sql** saves the whole database (schema, rows, indexes, views) as SQL you can load into an empty database with any SQLite tool or paste back into the console. Exports include up to 100,000 rows per table. - **Keys.** Filter by prefix, open a key to read or edit its value (up to 1 MB here), set an expiry, or delete it. - **Files.** Browse folders, upload files up to 25 MB each, download or delete them. Downloads always save as a file, so uploaded HTML never runs in the dashboard. Your code can write files of any size. ## Preview copies On a database, key-value store or file storage page, **Give previews their own copy** creates an empty copy that preview deployments use under the same binding, so `env.DB` in a preview branch never touches production data. New preview deployments pick it up; production is unchanged. A **Production / Preview copy** switch at the top of the page moves between the two. For a database, **Copy production data here** replaces the copy's contents with production's tables, rows (up to 100,000 per table), indexes and views, so you can test against real data. **Delete preview copy** sends previews back to production's data. Copies do not count against your plan's storage. ## Restore a database to a point in time Admins and owners can roll a database back to any minute in the last 30 days under **Restore to a point in time**, for example after a bad migration. Everything written since that moment is replaced, for every deployment that uses the database. Right after a restore, **Undo restore** brings back the state from just before it. Restores are recorded in the audit log. This uses point-in-time recovery, so it is not available in local mode. ## Connect your own Postgres Outgrown the built-in database? **Connect Postgres** on the Storage page takes a connection string from Neon, Supabase or any Postgres host and saves it, encrypted, as `DATABASE_URL` in every environment. Redeploy production to use it. HostEdge checks the string's format and warns about common mistakes (a Supabase direct host instead of the Transaction pooler, a Neon string without the pooler, SSL turned off); it does not open a connection. ```js import postgres from 'postgres' const sql = postgres(env.DATABASE_URL, { prepare: false }) const users = await sql`select * from users limit 10` ``` Use the host's pooled connection string when many visitors arrive at once, since each request is a short-lived connection. A database on your own computer can't be reached. ## Sign-in for your app A SQL database can also hold your app's users: see [Authentication](https://hostedge.app/docs/authentication). ## Limits | Plan | Storage per project | | ------- | ------------------- | | Free | 3 | | Starter | 10 | | Pro | 25 | | Agency | 50 | Storage counts every database, key-value store and file bucket together. Per-store platform limits apply too (for example, 10 GB per database). Each plan also includes an amount of data stored (databases and file storage together) and key-value operations per month; see [Limits](https://hostedge.app/docs/limits). HostEdge measures them about once an hour and shows them under **Settings › Billing › Usage this month**, and each storage page shows its own size. Going over does not stop anything; admins get a notice at 80 % and 100 %. ## Deleting **Delete…** on the storage page removes it with everything inside, including its preview copy. Deleting a project deletes its storage too. Code that still uses the binding fails until you remove it, so redeploy afterwards. --- Source: https://hostedge.app/docs/authentication Markdown: https://hostedge.app/docs/authentication.md # Authentication HostEdge Auth adds sign-in to an app that runs on HostEdge. Your users live in **your** project database, so they never leave your project and you can query them with SQL. It works in a Worker or the server side of a framework. It covers: - email and password, with sessions - magic links (sign in from an emailed link) - password reset - optional email confirmation - sign-in with Google or GitHub - rate limits that slow down guessing and email abuse ## Set it up 1. Open **Project › Storage** and open a SQL database (add one if you have none). 2. In the **Authentication** panel choose **Set up authentication**. This creates the `auth_*` tables. 3. Download `hostedge-auth.ts` from the panel, or fetch it from `https://hostedge.app/auth-kit/hostedge-auth.ts`, and put it in your project. It is one file with no dependencies. 4. Use it in your Worker, then redeploy: ```js import { createAuth } from './hostedge-auth' export default { async fetch(request, env) { const auth = createAuth(env.DB, { env }) const response = await auth.handle(request) // everything under /auth/… if (response) return response const user = await auth.getUser(request) // { id, email } or null if (!user) return new Response('Sign in first', { status: 401 }) return new Response(`Hello ${user.email}`) }, } ``` Pass `env` so HostEdge can send your emails (see below). The panel also lists the people who signed up, with **Sign out everywhere**, **Disable** and **Delete** for each. ## Endpoints `auth.handle(request)` answers these. POSTs take a JSON body and must send `content-type: application/json`, which also protects them from cross-site forms. | Request | What it does | | ------------------------------------------------- | ----------------------------------------------------------- | | `POST /auth/sign-up` `{ email, password }` | Creates the account and signs in (or sends a confirmation) | | `POST /auth/sign-in` `{ email, password }` | Signs in | | `POST /auth/sign-out` | Ends this browser's session | | `GET /auth/me` | `{ user }`, or `{ user: null }` | | `POST /auth/magic-link` `{ email, next? }` | Emails a one-time sign-in link (creates the account if new) | | `GET /auth/verify?token=…&next=/` | The link in that email: signs in and redirects to `next` | | `POST /auth/reset-request` `{ email }` | Emails a password reset link | | `POST /auth/reset` `{ token, password }` | Sets the new password, signs out other devices, signs in | | `GET /auth/oauth/github` and `/auth/oauth/google` | Starts sign-in with the provider | Passwords need at least 8 characters. `next` only accepts paths on your own site. The reset email links to `/reset-password?token=…` on your site. Build that page: a form that sends the token and a new password to `POST /auth/reset`. ## Emails HostEdge sends the magic-link, reset and confirmation emails for you, from its own sender and with your project's name, so there is nothing to set up. Every deploy adds `HOSTEDGE_PROJECT_ID`, `HOSTEDGE_MAIL_URL` and `HOSTEDGE_MAIL_SECRET` to your Worker; passing `env` to `createAuth` is all it takes. | Plan | Auth emails per day, per project | | ------- | -------------------------------- | | Free | 50 | | Starter | 500 | | Pro | 2,000 | | Agency | 10,000 | One address receives at most 5 emails an hour from a project, and links can only point at your project's own addresses. To send them yourself (Resend, Postmark, anything), pass a function instead: ```js createAuth(env.DB, { sendEmail: async ({ to, kind, url }) => { // kind is 'magic_link', 'reset' or 'confirm' await myMailer.send({ to, subject: 'Your link', text: url }) }, }) ``` ## Confirm emails Add `confirmEmail: true` to make people click an emailed link before they can sign in with a password. Until then, `sign-in` answers `email_not_verified`. ## Google and GitHub Create an OAuth app with the provider and give it this redirect address: ``` https://your-site.example/auth/oauth/github/callback https://your-site.example/auth/oauth/google/callback ``` Store the client ID and secret as [environment variables](https://hostedge.app/docs/environment-variables) and pass them in: ```js createAuth(env.DB, { env, oauth: { github: { clientId: env.GITHUB_ID, clientSecret: env.GITHUB_SECRET }, google: { clientId: env.GOOGLE_ID, clientSecret: env.GOOGLE_SECRET }, }, }) ``` Link people to `/auth/oauth/github?next=/dashboard`. Only a provider's verified email is accepted, and signing in with a provider uses the same account as a magic link or password for that email. ## Security notes - Passwords are hashed with PBKDF2 (SHA-256, 100,000 iterations, the most a Worker allows). Session tokens are stored hashed, in an HttpOnly, Secure, SameSite=Lax cookie. - After 10 wrong passwords for an email, or 50 from one address, sign-in is locked for 15 minutes. Requests for links, resets and sign-ups are limited per email and per address. - Password reset gives the same answer and timing whether or not the account exists, so the form can't be used to find out who has an account. - If someone registers an email with a password and its real owner later proves the address (magic link, Google or GitHub), the earlier password is discarded. ## Errors Failures return JSON like `{ "error": "invalid_credentials" }` with a matching status: `invalid_email` and `weak_password` (400), `email_taken` (409), `invalid_credentials` (401), `too_many_attempts` (429), `disabled` and `email_not_verified` (403), `email_unavailable` (503), `invalid_token` and `oauth_failed` (400). ## Limits HostEdge Auth keeps its tables in your project database, so users count toward your storage and request allowances like any other data. It suits apps up to a few thousand concurrent users; see [Databases and storage](https://hostedge.app/docs/storage) for connecting your own Postgres when you outgrow that. --- Source: https://hostedge.app/docs/cron-jobs Markdown: https://hostedge.app/docs/cron-jobs.md # Cron jobs A cron job calls a path on your production site on a schedule: send the daily digest, clear expired sessions, sync with another API. Open **Project › Cron jobs › New cron job**, give it a name and a path like `/api/cron/digest`, and pick a schedule. Schedules are standard cron expressions: minute, hour, day of month, month, day of week, read in the job’s time zone (your browser’s, unless you pick another; UTC is in the list too). `0 9 * * *` in Europe/Berlin stays at 09:00 Berlin time through daylight saving changes. A time skipped when clocks spring forward runs right after the jump; a time that happens twice when clocks fall back runs once. The dashboard offers common schedules and shows the next three runs as you type. | Expression | Runs | | -------------- | ------------------------ | | `*/15 * * * *` | Every 15 minutes | | `0 * * * *` | Every hour, on the hour | | `0 9 * * *` | Every day at 09:00 | | `30 8 * * 1-5` | Weekdays at 08:30 | | `0 0 1 * *` | The first of every month | `@hourly`, `@daily`, `@weekly` and `@monthly` work too. ## Your endpoint HostEdge sends a `GET` (or `POST` with a small JSON body, if you choose it) to your production URL. A response from 200 to 299 counts as success. Redirects are not followed, so point the job at the final path. Calls give up after 30 seconds. Every call carries a secret, and every deployment gets it as the `HOSTEDGE_CRON_SECRET` environment variable, so your endpoint can refuse anyone else: ```js export default { async fetch(request, env) { const url = new URL(request.url) if (url.pathname === '/api/cron/digest') { if (request.headers.get('authorization') !== `Bearer ${env.HOSTEDGE_CRON_SECRET}`) return new Response('Unauthorized', { status: 401 }) await sendDigest(env) return new Response('ok') } return env.ASSETS.fetch(request) }, } ``` The secret is created with your first cron job; redeploy once so your code sees it. **Roll secret** creates a new one (redeploy again afterwards). The request also has `X-HostEdge-Cron: ` and a `HostEdge-Cron` user agent. ## Retries Under **If a run fails**, choose up to three retries. A failed scheduled run is tried again 1, 5 and 15 minutes later, as long as that is before the next scheduled run; the request body says `"trigger": "retry"`. A slot counts as failed only when its last retry fails too. Runs you start with **Run now** are not retried. ## History and alerts Click a job to see its last 50 runs: when, how long, the status code and the start of the response. **Run now** calls it immediately, which is the quickest way to test. After three failures in a row, members with the Developer role and up get a notification (and an email, unless they turned it off in **Account › Notifications**). The alert fires once until the job succeeds again. ## Limits | Plan | Jobs per project | Shortest interval | | ------- | ---------------- | ----------------- | | Free | 2 | 1 hour | | Starter | 10 | 5 minutes | | Pro | 50 | 1 minute | | Agency | 100 | 1 minute | --- Source: https://hostedge.app/docs/forms Markdown: https://hostedge.app/docs/forms.md # Forms and waitlists Turn on forms in **Project › Forms** (the **Waitlist page** template does it for you). From then on, any form on your site that posts to `/_hostedge/forms/` is stored. There is no backend to write and no third-party script. ```html
``` The name in the address (`waitlist`, `contact`, `feedback`…) creates the form on its first submission. Names use lowercase letters, digits, dashes and underscores. ## Special fields | Field | What it does | | ----------- | ------------------------------------------------------------------------------------------------------------ | | `email` | Checked for a valid address, used for waitlists and as the reply-to of notification emails | | `_gotcha` | Spam trap. Keep it hidden; submissions that fill it are dropped silently | | `_redirect` | A path on your site to send people to afterwards, e.g. `/thanks`. Without it they see a short thank-you page | Other fields starting with `_` are ignored. Up to 50 fields of 5,000 characters each, 32 KB of text in total. ## From JavaScript ```js const response = await fetch('/_hostedge/forms/contact', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ email, message }), }) // { ok: true } or { ok: false, error: '…' } ``` Forms only accept posts from their own site. ## File uploads Turn on **Accept file uploads** under **Options for all forms**, then give your form `enctype="multipart/form-data"` and a file input: ```html
``` Each submission can carry up to 3 files of 5 MB each. HostEdge reads each file's first bytes to tell its type and accepts images (PNG, JPEG, GIF, WebP), PDFs, Word, Excel and PowerPoint files, and `.txt`, `.csv` or `.md` text; anything else (HTML, SVG, scripts, programs) is refused with a message. Files are stored privately, appear with their submission, and always download as files from the dashboard, never open in the browser. They are deleted with their submission, by the plan's retention, or when the form or project is deleted. Webhooks and notification emails name the files but do not include them. ## Turnstile spam check For forms that attract bots, turn on **Spam check with Turnstile**. HostEdge sets up the check for your site's addresses (custom domains included, kept in step as you add them) and shows a snippet to add to your pages: ```html
``` Most visitors never see a challenge. Submissions without a passing check are refused with a message asking to try again. With the check on, every form of the project needs the snippet, including ones sent with `fetch` (send the `cf-turnstile-response` field). ## Double opt-in For waitlists and newsletters, turn on **Ask people to confirm their email** in a form's settings. Each new sign-up gets an email with a confirmation link; until they confirm, the submission shows as **Unconfirmed**, you are not notified and the webhook does not fire. Signing up again resends the link at most once an hour. Unconfirmed sign-ups are removed after 30 days. The CSV export has an `unsubscribe_url` column. Put each person's link in the emails you send them; opening it marks them **Unsubscribed** in HostEdge so you can leave them out next time. ## Spam and limits - The `_gotcha` trap and known bots are answered like a person, so they learn nothing, and nothing is stored. - Each sender can submit 10 times per 10 minutes per project. HostEdge keeps a salted hash of the IP address for this, never the address itself. - Waitlists: with **One entry per email** on (the default), signing up twice is accepted but stored once. | Plan | Submissions per month | | ------- | --------------------- | | Free | 100 | | Starter | 2,000 | | Pro | 20,000 | | Agency | 100,000 | When the month's submissions are used up, new ones are refused until the 1st or until you upgrade. Stored submissions are never deleted for that. ## Notifications and integrations Each submission is emailed to everyone with the Developer role or above, or to the addresses you list in the form's settings. Reply to the email to answer the sender. To send submissions to Zapier, Make, Slack or your own code, add a webhook in **Settings › Webhooks** with the `form.submitted` event. The payload includes the project, the form and every field. ## Reading and exporting Click a form to see its submissions, newest first, with a search across all fields. **Export CSV** downloads every submission; cells that start with `=`, `+`, `-` or `@` are prefixed with `'` so spreadsheets never run them as formulas. Developers and above can read submissions; viewers see only the list of forms. Submissions are kept for 90 days on Free, 1 year on Starter, 2 years on Pro and 3 years on Agency; older ones are deleted each night. Export them first if you need them longer. --- Source: https://hostedge.app/docs/analytics Markdown: https://hostedge.app/docs/analytics.md # Web analytics Turn analytics on in **Project › Analytics** and HostEdge adds a 1 KB tracker to every HTML page of the project for you, served from your own domain at `/_hostedge/script.js`. There is nothing to install, and ad blockers that block third-party analytics leave it alone. You see visitors, pageviews, bounce rate and session time; where visitors came from (channel, referrer, UTM source and campaign); top, entry and exit pages; countries; devices, browsers and systems; goals and funnels; and, once a payment provider is connected, revenue by each of those. Click any row to filter the whole dashboard to it, for example _Campaign: launch_ and _Country: France_. Filters live in the URL, so a filtered view can be bookmarked or shared. ## Cookies or cookieless By default the tracker sets two first-party cookies on your domain: `sd_vid` (a random visitor ID, one year) and `sd_sid` (the session, 30 minutes). Nothing is shared with other sites. In **cookieless mode** visitors are counted with a hash of the IP address, user agent, your project and the date, mixed with a secret, so no cookie is set and the same person counts as new each day. Revenue attribution needs cookies, because a payment can come days after the first visit. ## Goals Count a goal when someone clicks an element: ```html ``` Or from JavaScript, anywhere on the page: ```js window.hostedge('goal', 'newsletter_signup', { source: 'footer' }) ``` Goal names use lowercase letters, digits, dashes and underscores; other characters are converted. Up to ten `data-hostedge-goal-*` attributes or object keys become properties. ### From your server Report goals your backend knows about, like an account created after email confirmation. Create a key in **Analytics › Settings › Server-side goals**, then send the visitor's `sd_vid` cookie: ```sh curl -X POST https://hostedge.app/api/v1/goals \ -H "Authorization: Bearer sda_…" \ -H "Content-Type: application/json" \ -d '{"visitorId":"","name":"signup","metadata":{"plan":"pro"}}' ``` ## Funnels A funnel is 2 to 8 steps, each a page (end with `*` to match a prefix, like `/blog/*`) or a goal. A visitor counts for a step only after completing the steps before it, in order. ## Revenue Connect Stripe, LemonSqueezy or Polar in **Analytics › Settings › Revenue**: 1. Copy the webhook URL shown for the provider into its webhook settings and select the events listed. 2. Paste the webhook's signing secret into HostEdge. 3. Pass the visitor ID with each checkout, read from `window.hostedge.visitorId()` in the browser or the `sd_vid` cookie on your server. | Provider | Where the visitor ID goes | Events | | ------------ | ---------------------------------------------- | ----------------------------------------------------------------- | | Stripe | `metadata.hostedge_visitor_id` on Checkout | `checkout.session.completed`, `invoice.paid`, `charge.refunded` | | LemonSqueezy | `checkout_data.custom.hostedge_visitor_id` | `order_created`, `subscription_payment_success`, `order_refunded` | | Polar | `metadata.hostedge_visitor_id` on the checkout | `order.paid`, `order.refunded` | Each payment is attributed to the visitor's **first visit**: its channel, referrer, campaign, landing page, country and device. Renewals count as revenue in the month they are paid; refunds subtract. Only payments in the project's currency are added up. ## Ad spend and ROAS Enter what each campaign cost per month in **Analytics › Settings › Ad spend**, one at a time or as a CSV of `campaign,month,amount` lines exported from your ads account. The campaign must match the `utm_campaign` your ads link with. The campaigns table then shows spend and **ROAS** (revenue from the campaign's first-touch visitors divided by its spend) for the period you are looking at; a month's spend is spread evenly over its days, so a week shows a week's share. ## Live visitors The **Live** panel shows who is on the site in the last five minutes, on a dotted world map with one marker per country (bigger for more visitors) next to the pages they are on and where they came from. The same numbers are listed as text for screen readers. ## Time zone Pick the project's time zone in **Analytics › Settings**. It decides where "today" starts and ends, the daily buckets and the times on charts. It starts as UTC. ## Busy sites For sites with about a million events a month or more, the 90-day and 12-month views read from daily totals that HostEdge adds up each night, plus today's raw events, so they stay fast. On those views days are UTC days and a visitor who came on several days counts once per day; the dashboard says so under the chart. A view filtered by one channel, referrer, source, campaign, entry page, country or device reads that value's own daily totals too, as long as it was among the day's top 10 for that column (or the column had no more than 10 values that day); its revenue then counts payments whose first touch matches the filter. Other filters, several filters at once and shorter ranges count from the raw events. A site that just became busy catches up over a few nights and uses the raw events until then. ## Excluding visits Add paths to ignore in **Analytics › Settings**, like `/admin*`. To stop counting your own visits, open your site once with `?hostedge_ignore=1` (and `?hostedge_ignore=0` to count yourself again). Bots and crawlers are never counted. ## Public dashboard Share a read-only link to the dashboard from **Analytics › Settings › Public dashboard**, for an open-startup page or investors. Turning sharing off breaks the link at once. ## Limits | Plan | Events per month | History | | ------- | ---------------- | ------- | | Free | 20,000 | 30 days | | Starter | 200,000 | 1 year | | Pro | 2,000,000 | 2 years | | Agency | 10,000,000 | 3 years | When a workspace uses its monthly events, new visits stop being counted until the next month or an upgrade; everything collected stays visible. --- Source: https://hostedge.app/docs/logs-analytics Markdown: https://hostedge.app/docs/logs-analytics.md # Logs and analytics ## Runtime logs **Project › Logs** shows every request line, `console.log` output and uncaught exception from your site, newest first, for the last 7 days. Filter by level, type and text; the filters live in the URL so you can share a view. **Live** follows new lines as they happen. From the terminal: `hostedge logs` (add `-f` to follow). Each plan stores a number of log lines per day across the workspace (see [Limits](https://hostedge.app/docs/limits)). Past that, until midnight UTC, every error and exception is still kept but only 1 in 100 other lines, chosen per request so a request's lines stay together; the logs page says when this is happening. Request counts in Analytics are not affected. ## Analytics **Project › Analytics** charts requests and 5xx errors over 24 hours, 7 days or 30 days, with bandwidth, error rate, top paths, status classes and countries. Numbers are recorded by HostEdge's edge router for every request to your site, including static assets. ## Usage Requests and bandwidth also count toward your plan's monthly allowance, shown in **Settings › Billing & usage**. --- Source: https://hostedge.app/docs/ai-assistants Markdown: https://hostedge.app/docs/ai-assistants.md # AI assistants (MCP) HostEdge speaks the [Model Context Protocol](https://modelcontextprotocol.io), so the assistant you already code with can ship what it writes. Ask it to "put this landing page live" and it deploys, waits for the build and hands you the URL. ## Connect in one minute Most assistants connect with only the address: add `https://hostedge.app/api/mcp` as a remote MCP server (for Claude Code, `claude mcp add --transport http hostedge https://hostedge.app/api/mcp`). The assistant opens a HostEdge page where you sign in, pick the workspace it may use and press **Allow access**. It then renews its access on its own; the connection appears in **Settings › API tokens** under the assistant’s name followed by “(MCP)”, where you can revoke it. ### ChatGPT ChatGPT connects to remote MCP servers as a custom connector. This needs Developer mode, which OpenAI offers on some paid plans and may rename or move, so check [OpenAI's help](https://help.openai.com) if a menu below looks different. 1. In ChatGPT open **Settings** and find **Apps** (earlier called **Connectors**). Under **Advanced settings**, turn on **Developer mode**. 2. Choose **Create** and enter the name `HostEdge` and the server address `https://hostedge.app/api/mcp`. 3. Set authentication to **OAuth** and save. ChatGPT opens the HostEdge page where you sign in, pick the workspace it may use and press **Allow access**. 4. In a new chat, add the HostEdge connector from the tools menu and ask: "Deploy this and check the logs." Custom connectors are unverified by OpenAI, and ChatGPT asks before it runs a tool that changes something. Revoke the connection any time in **Settings › API tokens**. ### With an API token For clients without OAuth support, or for scripts: 1. Open **Workspace › Settings › API tokens** and press **Create a token for AI assistants**. The token is shown once. 2. Copy the snippet for your assistant from the same panel. For Claude Code: ```bash claude mcp add --transport http hostedge https://hostedge.app/api/mcp \ --header "Authorization: Bearer hostedge_…" ``` For Cursor, Windsurf and other clients, add this to `mcp.json`: ```json { "mcpServers": { "hostedge": { "url": "https://hostedge.app/api/mcp", "headers": { "Authorization": "Bearer hostedge_…" } } } } ``` The endpoint uses the Streamable HTTP transport and needs no local install. ## Teach it how HostEdge works Connecting gives the assistant the tools; the [Agent kit](https://hostedge.app/docs/agent-kit) gives it the know-how. Run `npx hostedge init --ai` in your project (or copy the files from the same settings panel) to add `AGENTS.md`, `CLAUDE.md`, a Cursor rule and a Claude Code skill that explain frameworks, bindings, environment variables, deploying, logs and rollbacks. ## What the assistant can do | Tool | What it does | | ------------------------------- | --------------------------------------------------------- | | `list_projects` | Projects with their URL and whether they are live | | `deploy_files` | Deploys files it wrote; creates the project if needed | | `deploy_github_repo` | Deploys a public GitHub repository into a new project | | `get_deployment` | Status, URL and the last build log lines | | `list_deployments`, `rollback` | History, and instant rollback to an earlier deploy | | `get_logs`, `list_errors` | Runtime logs and grouped errors, for debugging | | `set_env_vars`, `list_env_vars` | Write variables; values are never read back | | `create_database`, `run_sql` | A SQLite database for the project, and queries against it | | `get_analytics` | Visitors, top pages and sources | ## What it cannot do The AI token only carries the scopes listed in the panel: it can read and deploy projects, logs, analytics, variables and storage. It cannot read form submissions, delete projects, change members, domains or billing. Every call is limited to the token's workspace and rate limited like the API. Revoke the token at any time and the assistant loses access immediately. ## Docs for assistants Everything here is public and needs no token. An assistant that can fetch URLs can learn HostEdge without scraping HTML: | URL | What you get | | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------- | | [`/llms.txt`](https://hostedge.app/llms.txt) | A map of HostEdge: every docs page, the MCP endpoint, the API and the files below | | [`/llms-full.txt`](https://hostedge.app/llms-full.txt) | Every docs page as one Markdown file, in docs order, each with its URL | | `/docs/.md`, for example [`/docs/domains.md`](https://hostedge.app/docs/domains.md) | One docs page as clean Markdown (`text/markdown`), links already absolute | | [`/docs.md`](https://hostedge.app/docs.md) | The docs index as Markdown | | [`/api/docs/search?q=custom+domains`](https://hostedge.app/api/docs/search?q=custom+domains) | Search results as JSON, each with the page, section, snippet and its Markdown URL | | [`/api/v1/openapi.json`](https://hostedge.app/api/v1/openapi.json) | The OpenAPI 3.1 description of the REST API (and of the two JSON endpoints here) | | [`/api/status.json`](https://hostedge.app/api/status.json) | Platform status as JSON: overall state and each component's state and last check | ### How an assistant should use them 1. To answer a question about HostEdge, call the search endpoint first, then fetch the `markdownUrl` of the best result. Fetching a page is cheaper and cleaner than parsing its HTML. 2. To read everything at once, fetch `/llms-full.txt`. It is a few tens of thousands of tokens, so prefer a single page when you know which one you need. 3. Every docs page also advertises its Markdown twin in a `link rel="alternate" type="text/markdown"` tag, and the page footer links to it. 4. To act (deploy, read logs, set variables), use the [MCP server](https://hostedge.app/docs/ai-assistants#connect-in-one-minute) or the [API](https://hostedge.app/docs/api), not the docs. 5. Before blaming HostEdge for a failed call, read `/api/status.json`. It answers 200 with `"status": "operational"`, `"degraded"` or `"down"`; each entry in `components` has its own `status` and `updatedAt`. ### Search ```bash curl "https://hostedge.app/api/docs/search?q=custom+domains&limit=3" ``` The response is `{ "results": [...] }`, best match first. Each result has `title`, `url` (the HTML page, with a `#section` anchor), `markdownUrl`, `section`, `snippet` and `score`. `q` takes 2 to 200 characters and `limit` 1 to 20 (default 5). Matching ignores case and accents, and words in a page title or heading count more than words in the text. The endpoint allows cross-origin `GET` requests and is limited per IP address: a `429` carries a `Retry-After` header. ### Status ```bash curl https://hostedge.app/api/status.json ``` ```json { "status": "operational", "updatedAt": "2026-01-01T12:00:00.000Z", "components": [ { "id": "routing", "name": "Sites (edge routing)", "status": "operational", "detail": "Requests are being routed.", "updatedAt": "2026-01-01T12:00:00.000Z", "uptime90d": 0.9998 } ] } ``` It shows what the [status page](https://hostedge.app/status) shows and is cached for 30 seconds. A component's `status` is `operational`, `degraded`, `paused` or `down`; `uptime90d` is the share of healthy checks over 90 days, or `null` for components without history. For a plain up or down check, use [`/api/health`](https://hostedge.app/api/health), which answers 503 when a dependency is down. --- Source: https://hostedge.app/docs/agent-kit Markdown: https://hostedge.app/docs/agent-kit.md # Agent kit The agent kit is a small set of instruction files for the assistant that writes your code. Drop them into a project and the assistant knows which frameworks HostEdge supports, how static and server deploys differ, how to use databases and environment variables, how to deploy, wait for the build, read logs and roll back, and which rules to follow (never commit secrets, redeploy after changing variables). It is generated from the same code as the dashboard, so the framework list and plan limits never go stale. ## Add it to a project From the project folder: ```sh npx hostedge init --ai # links the folder to a project and writes the kit npx hostedge ai-kit # only the kit; needs no account ``` Or download the files with `curl`: ```sh curl -fsSL https://hostedge.app/agent-kit/AGENTS.md -o AGENTS.md curl -fsSL https://hostedge.app/agent-kit/CLAUDE.md -o CLAUDE.md mkdir -p .cursor/rules .claude/skills/hostedge curl -fsSL https://hostedge.app/agent-kit/hostedge.mdc -o .cursor/rules/hostedge.mdc curl -fsSL https://hostedge.app/agent-kit/SKILL.md -o .claude/skills/hostedge/SKILL.md ``` You can also copy each file from **Settings › API tokens › Copy instructions for your assistant**. | File | Read by | | ---------------------------------- | ---------------------------------------------------------- | | `AGENTS.md` | Claude Code, Codex, Cursor, Windsurf and most other agents | | `CLAUDE.md` | Claude Code. It only imports `AGENTS.md` | | `.cursor/rules/hostedge.mdc` | Cursor, as a rule the agent applies when it is relevant | | `.claude/skills/hostedge/SKILL.md` | Claude Code, as a skill it loads on demand | The CLI never overwrites a file whose content differs unless you pass `--force`; it prints what it wrote (`+` created, `~` overwritten, `=` unchanged, `!` kept) and running it twice changes nothing. If you already have an `AGENTS.md`, keep it and paste the HostEdge section into it. `.cursor` and `.claude` folders are never deployed. ## Give the assistant access The kit tells the assistant how to work; it still needs permission to deploy. Pick one: - **MCP server.** Add `https://hostedge.app/api/mcp` to the assistant. See [AI assistants](https://hostedge.app/docs/ai-assistants). - **CLI with a token.** Create a token in **Settings › API tokens** and set it as `HOSTEDGE_TOKEN` in the assistant's environment. ## A CLI made for agents Every `hostedge` command works without a person at the keyboard. - `--json` puts machine-readable output on stdout and every human line (progress, build log, tips) on stderr. The two never mix. `hostedge logs --json` writes one JSON object per line (NDJSON). - `--yes`, `CI=1` or a missing terminal turn off every prompt. Commands never wait for input; when something is required they fail with a message that says what to pass. - `--quiet` hides progress. `hostedge deploy --quiet` prints only the URL. - `--api-url ` (or `HOSTEDGE_API_URL`) points at another HostEdge. `NO_COLOR` and `--no-color` turn colors off. - Tokens are never printed. `HOSTEDGE_TOKEN` is used as is and not written to disk; `hostedge login --with-token` reads a token from stdin and saves it (`--token ` also works but shows in the process list). ```sh # Who am I? { "user": …, "workspace": …, "scopes": […], "apiUrl": …, "tokenSource": "env" } npx hostedge whoami --json # Deploy and wait. Exit code 0 when live, 5 when the build fails. npx hostedge deploy --wait --json --yes # { "deploymentId": "dep_…", "status": "ready", "url": "https://….hostedge.app", # "projectId": "prj_…", "environment": "production", "failureReason": null } # Errors from the last hour, one JSON object per line. npx hostedge logs --json --level error --since 1h # { "id": "…", "timestamp": "2026-10-22T09:15:02.000Z", "level": "error", "type": "…", "message": "…" } ``` When a build fails, `deploy --wait --json` still prints the same object with `"status": "failed"` and the reason in `failureReason`, and exits with 5. With `--json`, any other failure prints `{ "error": { "code": "auth", "message": "…", "exitCode": 3 } }` on stdout and the message on stderr. `hostedge logs` accepts `--since` as minutes, hours or days up to 7 days (`30m`, `6h`, `7d`) and `--level` as `debug`, `info`, `warn` or `error`. ### Exit codes | Code | Name | Meaning | | ---- | --------------- | ------------------------------------------------------------------ | | 0 | `ok` | Success. | | 1 | `failure` | Generic failure (network error, bad input, unexpected). | | 2 | `usage` | Usage error: unknown flag or command, missing input. | | 3 | `auth` | Not signed in, token invalid, expired, revoked or missing a scope. | | 4 | `not_found` | Project, deployment or linked folder not found. | | 5 | `deploy_failed` | The deployment failed or was canceled. | | 6 | `limit` | A plan limit was reached (projects, size, storage …). | The same table is in `hostedge --help`. See [CLI](https://hostedge.app/docs/cli) for every command. ## What the kit teaches - **Static or server.** Which output each [framework](https://hostedge.app/docs/frameworks) produces and what runs on a Worker. - **Bindings.** `env.DB` (SQL), `env.KV` and `env.FILES` (files), created in **Storage** or with `create_database`, and a redeploy to connect them. - **Environment variables.** `set_env_vars`, build time versus runtime, and redeploying after a change. - **Deploy, wait, debug, roll back.** With the CLI (`--json`) or the MCP tools, polling `get_deployment` until the status is `ready` or `failed`. - **Limits.** The plan table from [Limits](https://hostedge.app/docs/limits), and what to do at exit code 6. - **Rules.** Never commit secrets, never print the token, do not invent features. --- Source: https://hostedge.app/docs/cli Markdown: https://hostedge.app/docs/cli.md # CLI ```sh npx hostedge login # opens your browser to authorize npx hostedge deploy # uploads changed files and streams the build ``` ## Install Run it without installing (`npx hostedge`), or install it once: ```sh npm install --global hostedge # or curl -fsSL https://hostedge.app/install.sh | sh ``` It needs Node.js 20.11 or newer. Then `hostedge login` and `hostedge deploy` work from any folder. ## Commands | Command | What it does | | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `hostedge login` | Opens HostEdge in your browser; pick a workspace and the CLI receives a 90-day token. `--token ` skips the browser; `--with-token` reads the token from stdin. | | `hostedge logout` | Forgets the token on this computer. Revoke it in **Settings › API tokens**. | | `hostedge whoami` | The account, workspace and scopes in use. | | `hostedge ai-kit` | Writes `AGENTS.md`, `CLAUDE.md`, a Cursor rule and a Claude Code skill. See [Agent kit](https://hostedge.app/docs/agent-kit). `--force` overwrites. | | `hostedge init` | Links the folder to a new or existing project (`--project `). Writes `.hostedge/project.json` and adds it to `.gitignore`. `--ai` also writes the agent kit. | | `hostedge deploy` | Deploys the folder. `--preview` for a preview, `-m` for a message, `--no-wait` to return after queueing. Exits with 5 if the build fails. | | `hostedge logs` | Runtime logs. `-f` follows, `--level error`, `--search `, `--since 30m\|1h\|24h\|7d`. | | `hostedge env pull` | Writes variables to `.env.local` (mode 600, git-ignored). `-e production` for another environment. | | `hostedge share [port]` | A public HTTPS link (and QR code) to a dev server on your computer, to try it on your phone. See [Share localhost](https://hostedge.app/docs/share-localhost). | The first `hostedge deploy` in an unlinked folder creates the project and links it. ## Scripts and agents Every command takes these options: | Option | Effect | | ----------------- | --------------------------------------------------------------------------------------------------------------- | | `--json` | Machine-readable output on stdout (NDJSON for `logs`). Progress and human text go to stderr, never to stdout. | | `-y`, `--yes` | Never prompt. `CI=1` and a missing terminal do the same; commands fail with a clear message instead of waiting. | | `-q`, `--quiet` | Only results and errors. `hostedge deploy -q` prints only the URL. | | `--api-url ` | Use another HostEdge for this run (same as `HOSTEDGE_API_URL`). | | `--no-color` | Plain text. `NO_COLOR` is respected too. | ```sh hostedge deploy --wait --json # {"deploymentId":"dep_…","status":"ready","url":"https://….hostedge.app","failureReason":null,…} ``` If the build fails the same JSON is printed with `"status":"failed"` and the reason in `failureReason`, and the exit code is 5. Tokens are never printed: use `HOSTEDGE_TOKEN`, or pipe one to `hostedge login --with-token`. ### Exit codes | Code | Meaning | | ---- | ----------------------------------------------------------------------- | | 0 | Success | | 1 | Generic failure | | 2 | Usage error (unknown flag or command, missing input) | | 3 | Authentication error (not signed in, token invalid, expired or revoked) | | 4 | Not found (project, deployment or linked folder) | | 5 | Deployment failed or was canceled | | 6 | A plan limit was reached | More in [Agent kit](https://hostedge.app/docs/agent-kit). ## Continuous integration Create a token in **Settings › API tokens** with the `deployments:write` and `projects:read` scopes, store it as a secret, and run: ```yaml - run: npx hostedge deploy --message "${{ github.sha }}" env: HOSTEDGE_TOKEN: ${{ secrets.HOSTEDGE_TOKEN }} ``` ## What gets uploaded The same rules as the dashboard: `.git`, `node_modules` and similar folders are skipped, files that look like secrets are left behind with a note, and symbolic links are refused. --- Source: https://hostedge.app/docs/share-localhost Markdown: https://hostedge.app/docs/share-localhost.md # Share localhost Building on your laptop and want to see it on your phone, or show a client? One command gives your dev server a public HTTPS link: ```bash npx hostedge share 5173 ``` Use the port your dev server prints (Vite 5173, Next.js 3000, Astro 4321…). The terminal shows the link and a QR code: scan it with your phone's camera. Press **Ctrl+C** to close the link. ## Signed in or not - **Signed in** (`hostedge login`): you get a link like `https://amber-cedar-ab12--share.hostedge.app`. It appears on your workspace's Projects page with a QR code, where teammates can open it and anyone with the Developer role can stop it. Links close after 2 hours on the Free plan and 8 hours on paid plans; Free has one open link at a time, Starter 2, Pro 5, Agency 20. - **Not signed in**, or with `--quick`: you get an anonymous temporary link. It works without an account, has no uptime guarantee and closes with Ctrl+C. ## Dev servers that check the host Vite, Next.js and others refuse requests for unknown hostnames. HostEdge sends your dev server `Host: localhost`, so it works without changing its config. To send something else, use `--host-header`: ```bash npx hostedge share 3000 --host-header myapp.test ``` ## How it works The CLI runs a small open-source tunnel helper on your machine (it uses one on your `PATH`, or downloads it once to `~/.hostedge/bin`). It opens an outbound connection, so nothing on your computer is exposed except that one port, and no firewall or router changes are needed. Anyone with the link can open your dev server while it runs, so do not share links to anything private. --- Source: https://hostedge.app/docs/api Markdown: https://hostedge.app/docs/api.md # API ## Tokens Create tokens in **Settings › API tokens**. A token acts as you in one workspace, limited to the scopes you choose, and stops working if you leave the workspace. It is shown once; HostEdge stores only a hash. Send it as a bearer token: ```sh curl -H "Authorization: Bearer $HOSTEDGE_TOKEN" https://hostedge.app/api/v1/me ``` | Scope | Allows | | ------------------- | -------------------------------------- | | `projects:read` | List and read projects and deployments | | `projects:write` | Create and change projects | | `deployments:write` | Upload files and create deployments | | `logs:read` | Read runtime logs | | `env:read` | Pull environment variables | | `env:write` | Change environment variables | Members, billing, tokens, webhooks and deleting things are never available to tokens. They need a signed-in person. ## Endpoints The full description is at [`/api/v1/openapi.json`](https://hostedge.app/api/v1/openapi.json) (OpenAPI 3.1), for generating a client: ```sh npx openapi-typescript https://hostedge.app/api/v1/openapi.json -o hostedge-api.d.ts ``` | Method and path | Purpose | | -------------------------------------- | --------------------------------------------------------------------------- | | `GET /api/v1/me` | The person, workspace and scopes of the token | | `GET /api/v1/projects` | Projects in the token's workspace | | `POST /api/v1/projects` | Create a project (`name`, `settings`) | | `GET /api/v1/projects/:id/deployments` | Deployments, newest first | | `POST /api/v1/uploads` | Which of these content hashes still need uploading (`hashes`) | | `PUT /api/v1/uploads/:hash` | Upload one file's bytes | | `POST /api/v1/uploads/batch` | Upload many small files at once (multipart, each field named by its hash) | | `POST /api/v1/deployments` | Create a deployment from uploaded files (`files`, `projectId` or `project`) | | `GET /api/v1/deployments/:id/events` | Build log and status as Server-Sent Events | | `GET /api/v1/deployments/:id/explain` | Why a deployment failed, with fixes and a prompt for an AI assistant | | `GET /api/v1/projects/:id/logs` | Runtime logs (`level`, `q`, `range`, `before`) | | `GET /api/v1/projects/:id/env` | Variables for an environment (`format=dotenv` for a file) | ### Explaining a failed deployment `GET /api/v1/deployments/:id/explain` turns the failure reason and the last 300 lines of the build log into a diagnosis, without calling an AI model. It needs the `projects:read` scope and works for failed, canceled, held and rejected deployments; for a running or successful one it answers `{ "applicable": false, "reason": "in_progress" | "succeeded" }`. ```json { "applicable": true, "deploymentId": "dep_…", "status": "failed", "reviewStatus": "none", "explanation": { "category": "missing-module", "ruleId": "module-not-found", "title": "Package “date-fns” couldn’t be found", "summary": "…", "likelyCause": "…", "fixes": ["Run `npm install date-fns` …"], "settingsToCheck": [{ "field": "Root directory", "suggestion": "…" }], "docsPath": "/docs/frameworks", "confidence": "high", "assistantPrompt": "A deployment of my project on HostEdge …" } } ``` `assistantPrompt` is ready to paste into an AI assistant. It contains the framework, settings, diagnosis and at most 40 log lines, with tokens, bearer headers and `KEY=value` secrets removed. Explanations are rate limited to 120 requests a minute per workspace. Errors are JSON: `{ "error": { "code": "forbidden", "message": "…" } }`. Tokens are rate limited to 600 requests a minute. --- Source: https://hostedge.app/docs/webhooks Markdown: https://hostedge.app/docs/webhooks.md # Webhooks Admins can add endpoints in **Settings › Webhooks**. HostEdge POSTs JSON to them when subscribed events happen. ## Events | Event | When | | ------------------- | ------------------------------------------------ | | `deployment.ready` | A deployment finished and is live | | `deployment.failed` | A deployment failed | | `domain.verified` | A custom domain's DNS and certificate are active | | `project.created` | A project was created | | `project.deleted` | A project was deleted | | `form.submitted` | A form on a project received a submission | **Send test** delivers a `ping` event. ## Payload ```json { "id": "evt_01m4…", "type": "deployment.ready", "createdAt": "2026-10-07T12:00:00.000Z", "workspace": { "id": "wsp_…", "slug": "acme" }, "data": { "deployment": { "id": "dep_…", "url": "https://…" }, "project": { "slug": "shop" } } } ``` Headers: `X-HostEdge-Event`, `X-HostEdge-Delivery` (unique per delivery) and `X-HostEdge-Signature`. ## Verifying signatures `X-HostEdge-Signature` is `t=,v1=`, where the hex is HMAC-SHA256 of `"."` with your endpoint's signing secret. Reject old timestamps to stop replays. ```js import { createHmac, timingSafeEqual } from 'node:crypto' export function verify(secret, rawBody, header, toleranceSeconds = 300) { const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('='))) if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSeconds) return false const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex') return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected)) } ``` ## Retries Answer with any 2xx within 10 seconds. Otherwise HostEdge retries after 30 seconds, 2 minutes, 10 minutes, 1 hour and 6 hours, then marks the delivery failed. Every attempt is in the delivery log with the status code and the start of your response, and you can redeliver any event. If every delivery to an endpoint fails for 3 days, with no success in between, HostEdge turns the endpoint off, stops retrying, and tells the workspace’s Admins in the dashboard and by email. Fix the endpoint, switch it back on, and redeliver what you missed from the log. --- Source: https://hostedge.app/docs/teams Markdown: https://hostedge.app/docs/teams.md # Teams and roles Every account has a personal workspace. Create team workspaces to share projects, domains and billing. | Action | Viewer | Developer | Admin | Owner | | --------------------------------------------------------- | :----: | :-------: | :---: | :---: | | See projects, deployments, logs | ✓ | ✓ | ✓ | ✓ | | Deploy, roll back, manage domains and variables | | ✓ | ✓ | ✓ | | Create API tokens | | ✓ | ✓ | ✓ | | Delete projects, manage members and webhooks, see billing | | | ✓ | ✓ | | Change the plan, transfer or delete the workspace | | | | ✓ | ## Invites Admins invite by email. Invites expire after 7 days and can be resent or revoked; pending invites count as seats. ## Transfer ownership The owner can make another Admin the owner from **Settings › Members**. They become an Admin. ## Transfer a project Finished a site for a client? Hand it over from **Project › Settings › Transfer project**. Admins and the Owner can transfer. - **Move to one of your workspaces**: pick the workspace and confirm by typing the project's name. It moves immediately. - **Send to someone else**: create a transfer link, optionally emailed to your client. They sign in (or create a free account), pick one of their workspaces and accept. Links work once, for 7 days, and you can cancel them. The site stays online throughout. Domains, deployments (with instant rollback), environment variables, databases and storage, cron jobs, forms, monitors and analytics all move with the project. From the moment of transfer, usage counts against the new workspace's plan, which must have room for the project and its custom domains. A GitHub connection moves only if the new workspace has access to the same GitHub installation; otherwise reconnect the repository after the transfer. Both workspaces' audit logs record the transfer. --- Source: https://hostedge.app/docs/limits Markdown: https://hostedge.app/docs/limits.md # Limits and fair use | Limit | Free | Starter ($9/mo) | Pro ($29/mo) | Agency ($79/mo) | | --- | ---: | ---: | ---: | ---: | | Projects | 3 | 10 | 50 | Unlimited | | Custom domains | 1 | 5 | 25 | 100 | | Members | 1 | 3 | 10 | 25 | | Requests per month | 100,000 | 1,000,000 | 10,000,000 | 50,000,000 | | Bandwidth per month | 10 GB | 100 GB | 500 GB | 2000 GB | | CPU time per request | 10 ms | 30 ms | 50 ms | 50 ms | | Subrequests per request | 50 | 100 | 500 | 1,000 | | Deployment size | 50 MB | 250 MB | 250 MB | 250 MB | | Files per deployment | 2,000 | 20,000 | 20,000 | 20,000 | | Runtime log lines per day | 20,000 | 200,000 | 2,000,000 | 10,000,000 | | Analytics events per month | 20,000 | 200,000 | 2,000,000 | 10,000,000 | | Analytics history | 30 days | 365 days | 730 days | 1095 days | | Form submissions per month | 100 | 2,000 | 20,000 | 100,000 | | Form submissions kept for | 90 days | 365 days | 730 days | 1095 days | | Uptime monitors per project | 2 | 10 | 50 | 100 | | Uptime checks as often as every | 5 min | 1 min | 1 min | 1 min | | Databases and storage per project | 3 | 10 | 25 | 50 | | Data stored (databases and files) | 1.0 GB | 10 GB | 100 GB | 500 GB | | Key-value operations per month | 1,000,000 | 10,000,000 | 50,000,000 | 200,000,000 | | Cron jobs per project | 2 | 10 | 50 | 100 | | Cron jobs as often as every | 1 hour | 5 minutes | minute | minute | ## Monthly allowances Requests and bandwidth reset on the 1st of each month (UTC). You get an email and a notice in the dashboard at 80 % and at 100 %. When a workspace uses its whole **request** allowance, its sites answer with a short “temporarily over its limit” page until the month resets or you upgrade. Upgrading lifts it within seconds. Going over the **bandwidth** allowance doesn't take sites down; you'll be asked to upgrade. Data stored in databases and file storage, and key-value operations, are measured about once an hour. Going over them doesn't take anything down either; admins get a notice at 80 % and 100 %. Sign-in emails sent by [Authentication](https://hostedge.app/docs/authentication) are limited per project per day: 50 on Free, 500 on Starter, 2,000 on Pro and 10,000 on Agency. Projects, custom domains and seats are checked when you add one; nothing existing is removed if you downgrade. ## Overage on paid plans On a paid plan, the workspace owner can turn on **Bill usage past the allowance** under **Settings › Billing**. Sites then keep running after the month's requests run out, and what you use beyond the plan is billed with your subscription: $0.50 per million requests and $0.10 per GB of bandwidth. Pick a monthly cap ($10 to $250); once this month's overage reaches it, sites pause as they would without overage, and you get a notice. Overage is sent to billing once a day, so the last day of a billing period can show up on the following invoice. ## Changing plans Subscribers switch between paid plans on the billing page. Before you confirm, HostEdge shows what the switch costs right now: the price difference for the rest of the billing period is charged at once when you move up, or credited toward your next invoices when you move down. New limits apply immediately. To cancel, use **Manage billing**. ## First-deploy checks Sites from free accounts in their first 14 days are checked for phishing pages, wallet drainers and hidden loaders before they go live. Almost every site passes instantly. If one matches, it waits for a person to look at it. Usually within a few hours. And you get an email either way. ## Acceptable use Hosting phishing, malware, spam or content that breaks the law gets sites suspended and accounts closed. Read the [Acceptable Use Policy](https://hostedge.app/legal/acceptable-use). To report a site, use the [report form](https://hostedge.app/abuse).