# Percher > AI-native hosting for personal and small-scale apps: things people build for themselves, their family, a club or association, or a smaller business. Deploy in seconds via CLI or AI assistant. Live at name.percher.run with SSL, logs, rollback, and an opt-in managed PocketBase sidecar. Not positioned as production-grade hosting today: no uptime SLA, no formal compliance, single region in Germany. > > This file is the full documentation corpus for agent consumption (llmstxt.org). For human-friendly browsing see https://percher.app/docs; for an orientation summary see /llms.txt. ## Pricing - Free (free) — 512MB RAM pool, 0.5 vCPU pool, 1GB disk pool, up to 3 apps, 50 live + 25 preview deploys/day, 5 rollbacks, sleep after idle - Starter (€3/mo) — 1.5GB RAM pool, 1 vCPU pool, 5GB disk pool, up to 10 apps, 100 live + 50 preview deploys/day, 15 rollbacks, always-on - Maker (€12/mo) — 4GB RAM pool, 2 vCPU pool, 25GB disk pool, up to 20 apps, 200 live + 100 preview deploys/day, 30 rollbacks, always-on - Pro (€29/mo) — 10GB RAM pool, 4 vCPU pool, 75GB disk pool, up to 40 apps, 1000 live + 500 preview deploys/day, 60 rollbacks, always-on ## Connecting an AI assistant (MCP) Run `bunx percher mcp` to print the MCP server config for Claude Code, Cursor, Windsurf, and VS Code. The server exposes 49 tools including `percher_publish`, `percher_wait_for_deploy`, `percher_doctor`, and `percher_logs`. The recommended flow is async: `percher_publish` returns immediately with a queued deploy ID (MCP defaults waitForLive=false), then `percher_wait_for_deploy` short-polls until live or routes to `percher_doctor` for recovery. ## Quick start Most people never touch a terminal. You tell your AI assistant to publish, and it does the rest. Percher is built to be driven by your AI assistant: Claude, Cursor, Windsurf, or whatever you build with. Already have code from an AI assistant — a Claude artifact, a Lovable project, something ChatGPT wrote? You're most of the way there. Drop it into a folder, run `init`, run `publish`, and it's live at `yourname.percher.run`. Haven't built anything yet? Percher hosts your app, it doesn't build it for you, but the thing you want to host is closer than you think: describe it to an AI assistant, get a working site or small app back, and publish it here. ## Tell an AI what to build You don't need to write the code. Pick whichever you're most comfortable with and describe what you want in a sentence or two: - **AI app builders (Lovable, v0, Bolt).** Describe an app and they generate a working project you can download. Best for something interactive with a few screens. - **Claude or ChatGPT.** Ideal for a single-page site or a small tool. Ask for the files, then save them into one folder. (A claude.ai artifact runs in a sandboxed preview, so copy the code out — or download the zip if Claude provides one.) - **Cursor or Claude Code (in your editor).** For when you want to keep tweaking. They edit files in place, and once you connect Percher's MCP server they can publish for you too. One tip that saves trouble later: ask for a static site (plain HTML or a framework that builds to files) or a simple Node or Bun app, and skip platform-specific features like edge functions. The prompt starters below already bake that in. ## Prompt starters Copy one, swap in your own details, and paste it into your AI. Each is written so the result publishes on Percher without extra setup. **Personal site / portfolio** — A single page about you and your work. The simplest thing to build and host. ``` Build a one-page personal portfolio as plain HTML, CSS, and JavaScript with no framework. Include a hero with my name and what I do, a projects grid, and a contact section. Keep it a static site I can deploy as-is, no build step. ``` **Link in bio** — A tidy page of links for your social profiles. ``` Build a single-page 'link in bio' site as static HTML and CSS. A round avatar, my name, a one-line bio, and a vertical list of tappable link buttons. Mobile-first, no build step. ``` **Blog** — Posts you write in Markdown, rendered as a clean readable site. ``` Create a blog as an Astro site with three example posts in Markdown, a home page that lists them, and a clean readable layout. Produce static output that's ready to deploy. ``` **Landing page for an idea** — One page to explain a product and collect interest. ``` Build a landing page for [describe your idea] as a static Vite + React site: a headline, three benefit cards, and an email signup form wired to a hosted form service so it works without a backend. Use either a Formspree endpoint (a plain POST form) or an embedded Tally form; I'll paste mine. Keep it a static build with no server. ``` **A small tool or web app** — Something interactive that remembers data between visits. ``` Build a small [todo / expense tracker / habit tracker] web app as a Node app using Express. Store data in a SQLite file at /app/data/app.db (Percher mounts /app/data as a persistent volume, so create the directory if needed and keep all data there so it survives redeploys). Include a package.json with a start script, and read the port from the PORT environment variable. ``` **A simple API** — A few JSON endpoints for another app to call. ``` Build a small JSON API in Node with Express: two or three endpoints plus a /health route. Read the port from the PORT environment variable and include a package.json with a start script. ``` ## What the AI built, and which runtime Percher picks You don't need to know which runtime your app is — `init` detects it from the files. These cover roughly what AI assistants generate: - **A React + Vite single-page app** — the most common Claude artifact shape. Served as a static build: a Bun stage compiles the bundle, a slim Caddy image serves it, with SPA routing and SSL baked in. - **A Next.js app** — detected from next.config.js and run on the Node runtime. Server Components, Server Actions, and ISR work unchanged. Edge Functions become regular API routes. - **An Express, Hono, or Fastify API** — detected from package.json and run as a long-running Node server. Add a /health route that returns 200 and the deploy health check passes. - **A Bun server** — a Bun.serve handler ships on the Bun runtime: fast cold builds, native HTTPS proxy, no Node compatibility shims. - **A Python FastAPI, Flask, or Django app** — detected from requirements.txt or pyproject.toml and built via Nixpacks, which auto-detects the framework. - **Static HTML or a landing page** — no build step, just files served by Caddy in a few-MB container. Instant cold start, automatic SSL. If `init` guesses wrong, the `runtime` field in `percher.toml` is a one-line override. ## Publish it Once you have a folder with your project, say to your assistant: "Publish my app to percher.app." To update the live version later, say "Publish my latest changes to percher.app." The first time, your assistant opens a browser (or hands you a link) to sign in once. A couple of minutes later you get a link like `your-app.percher.run`, already secured with HTTPS. Prefer to run it yourself? Get your AI-generated files into a folder first (paste the artifact, or save what your assistant wrote), then run the CLI from that folder, via `bunx` (Bun) or `npx` (Node): ```sh # From the folder that holds your app's code, one command does everything: cd path/to/your-app bunx percher publish # login, config, build, deploy # Granular control (only when you need to isolate a single phase): bunx percher login bunx percher init bunx percher push ``` ## Is Percher right for this? Percher is for personal and small-scale apps: hobby sites, side projects, internal tools, an app for your family, a club or association, or a smaller business, the small thing you want online today. It runs in one region with no uptime SLA and no compliance certifications, so it isn't the right home for a paid SaaS or anything a customer depends on. ## Common questions **Do I need to know how to code?** No. You describe what you want in plain language and the AI writes the code. You do need to be able to copy files into a folder and run one publish command (or let an MCP-connected assistant run it for you). If a step is unclear, paste the error back to your assistant and ask it to fix it. **Which AI should I use?** For an interactive app, builders like Lovable, v0, or Bolt let you describe it and download a working project. For a single-page site or a small tool, Claude or ChatGPT will write the files and you save them. To keep tweaking, Cursor or Claude Code edit files in place and can publish for you once Percher's MCP server is connected. **Why do the prompts say 'static site' or 'read PORT'?** Those constraints make the result publish cleanly on Percher. A static site (plain HTML or a framework that builds to files) needs no server. A Node or Bun app needs to listen on the port Percher gives it via the PORT environment variable and have a start script. Ask for those and the first publish usually just works. **What can't I host here?** Percher is for small, self-contained sites and apps. It runs in one region, has no uptime SLA, and no compliance certifications. It isn't the right home for a paid SaaS or anything a customer depends on. For a hobby site, a side project, an app for your family or a club, or a tool for a smaller business, it's a good fit. ### Publishing AI-generated code **Can I deploy directly from claude.ai's artifact tab?** Not directly. claude.ai artifacts run in a sandboxed preview that doesn't deploy externally. Copy the code into a local folder (or download the artifact if Claude provides a zip), then run bunx percher publish from that folder. The whole loop takes about a minute including the build. **What about Claude Code, Cursor, or another MCP assistant?** That's the slickest path. Install Percher's MCP server (bunx percher mcp prints the config to paste into your assistant's settings) and it gets percher_publish, percher_logs, percher_doctor, and the rest as native tool calls. You ask it to ship the project, the build streams in the conversation, and the live URL comes back as a message — no tab switching. **What if the AI used an Edge Function or a host-specific API?** Convert it to the standard-Node equivalent. Edge functions (runtime: 'edge' in Next.js) become regular API routes. Vercel KV, Postgres, and Blob storage have no direct equivalent here: opt into the managed PocketBase sidecar with [data] mode = "pocketbase" for SQLite + auth + file storage, or point DATABASE_URL at any external Postgres. **What's the CLAUDE.md file, and do I need it?** Optional, but it helps. bunx percher ai-files install writes CLAUDE.md, .cursorrules, and .windsurfrules into your project. They teach the assistant exactly how to generate a working percher.toml, add a health endpoint, set env vars, and recover if a deploy fails — so the deploy instructions are baked into every prompt. Run bunx percher ai-files update later to refresh them. ## Recommended configurations by app type Starting points for `[resources]` and `[data]` in percher.toml, by app type. These are recommended sizing (your app's per-container cap) — your plan pool is charged on measured usage, not the cap, so pick what fits the app and adjust after deploying based on real usage. 256mb is the platform minimum. - **Static site / landing page**: memory 256mb, cpu 0.25. runtime "node" or "static", no `[data]`. (Astro static, Vite, 11ty, Hugo.) - **API service / webhook handler**: memory 256mb, cpu 0.5. Go/Rust fit 256mb; Python 256–512mb. Add `[data] mode = "pocketbase"` for storage. (Express, Fastify, Hono, Flask, FastAPI.) - **Fullstack SSR web app**: memory 512mb, cpu 0.5 (1gb for heavy image/SSR work). Next.js, Remix, SvelteKit, Nuxt, Astro SSR. - **Fullstack app with database**: memory 512mb, cpu 0.5, `[data] mode = "pocketbase"`. PocketBase gives SQLite + REST + auth + file storage + realtime; the app receives POCKETBASE_URL / POCKETBASE_PUBLIC_URL and an auto-created superuser; admin UI at pb-.percher.run/_/; the sidecar runs in its own 128mb container. - **Real-time app (WebSocket/SSE)**: memory 512mb (≈1mb per active connection; 1gb for 500+), cpu 0.5. Works through the Caddy proxy. - **Background worker / queue processor**: memory 256mb, cpu 0.5. Must still expose an HTTP `/health` endpoint on port 3000 so Percher can verify the container. - **Python data app / ML inference**: memory 1gb, cpu 1.0. numpy/pandas need ≥512mb. Large LLM/image models exceed Percher's limits (use a dedicated GPU service). 30-second health-check timeout. - **Go or Rust microservice**: memory 256mb, cpu 0.25. runtime "docker" via a multi-stage Dockerfile. - **Monorepo / multi-package app**: memory 512mb, cpu 0.5. Built from the project root; the start script must build and start the right package. - **PHP application (Laravel/Symfony)**: memory 256mb (512mb with queues), cpu 0.5. runtime "docker"; set APP_KEY via env. Full reference: https://percher.app/docs/recommended-setup ## CLI reference Run the CLI with `bunx percher ` (Bun) or `npx percher ` (Node). `percher publish` prints a pre-flight summary (detected framework, Node version + source, build/health/port, bundle size) before upload, and on failure surfaces the build-log tail, missing env vars, and any classified diagnosis inline. Pre-build infra failures are tagged `infra_unavailable` so you know to retry rather than fix code. Deploy: - `percher publish`: standard deploy (login, config, deploy, error diagnosis) - `percher publish --dry-run`: verify the bundle (file count, bytes) without uploading - `percher publish --preview`: deploy to a temporary preview URL (does not replace live) - `percher publish -m "note"`: add a note shown in deploy history - `percher publish --no-cache`: skip the image cache, force a fresh build - `percher push`: low-level upload + deploy only (prefer publish) - `percher rollback `: roll back to a previous version Setup: - `percher init`: create percher.toml - `percher create --template node`: new app from a template - `percher login`: authenticate via browser device flow - `percher whoami`: current user + token info - `percher open`: open the app URL Deploys and logs: - `percher deploys [app]`: list recent deploys - `percher deploys inspect ` / `--latest-failed`: full status + build log - `percher preview promote|discard `: promote/discard a preview - `percher logs [app] [--tail 50] [--build [id]]`: runtime or build logs - `percher doctor [app]`: recovery hub; diagnoses failures and prints the exact next action Env, data, domains: - `percher env set KEY=VAL | list | unset KEY` - `percher data [app]`: PocketBase status, collections, stats - `percher data reset-superuser [--reveal]`: rotate the PB superuser - `percher domains add|verify|list|remove ` - `percher versions`: deploy history with commit SHAs Full reference: https://percher.app/docs/cli-reference ## GitHub & CI/CD Three ways to deploy from GitHub. **Option A, Dashboard + GitHub App (public + private repos, recommended).** Install the Percher GitHub App from the GitHub section at percher.app/account#github and pick which repos to grant. Then click Deploy on a repo; auto-deploy on push is active immediately, no webhook config. AI agents can connect after the one-time install with `percher github connect owner/repo --app myapp`. (The GitHub section only appears once the App is configured on the instance — see the operator runbook if it's missing.) **Option B, Server-side webhook (public repos only).** Percher clones the repo and deploys on every push to the tracked branch, with no Actions runners or billing minutes. The app must already exist (run `bunx percher publish` once first). Then: ```sh bunx percher github connect https://github.com/owner/repo --branch main ``` It clones, queues a deploy, and prints a webhook secret. Add a GitHub webhook: Payload URL `https://api.percher.run/webhooks/github`, content type `application/json`, the printed secret (shown once), just the push event. Percher verifies the HMAC-SHA256 signature and ignores other branches. Recover a failed setup with `bunx percher github setup-webhook --app `. **Option C, GitHub Actions with PERCHER_TOKEN (public + private).** Create a token at percher.app/account → API token, add it as the Actions secret `PERCHER_TOKEN`, then run `bunx percher publish` in the workflow (use `--preview` on pull_request for preview deploys). The CLI auto-detects the branch from GITHUB_HEAD_REF / GITHUB_REF_NAME (also GitLab, Vercel, Netlify env vars) for the deploy note. Token auth works in any shell: `PERCHER_TOKEN= bunx percher publish` or save it with `bunx percher login --token `. Full guide: https://percher.app/docs/github-cicd ## Environment variables Env vars are encrypted at rest (AES-256-GCM) and injected at container startup. Changes take effect on the next deploy. ```sh bunx percher env set STRIPE_KEY=sk_live_... bunx percher env list # values are masked bunx percher env unset STRIPE_KEY ``` **Build-time exposure.** By default env vars are runtime-only (correct for secrets), which breaks frameworks like Vite/Next/Astro/Expo that bake `*_PUBLIC_*` values into the static bundle at build time. Opt in per key via `[build] pass_env` in percher.toml; values still come from the env store, not the TOML. For `runtime = "docker"` the listed keys are forwarded as `--build-arg` (declare a matching `ARG` in your Dockerfile). **Outbound HTTPS.** Apps run on an internal Docker network and reach the public internet through a forward proxy Percher injects automatically: `HTTP_PROXY`/`HTTPS_PROXY=http://egress-proxy:8888`, `NO_PROXY=localhost,127.0.0.1,.local`, `NODE_USE_ENV_PROXY=1`. Bun and Node 24+ use it automatically; Python (requests/httpx/urllib) and Go honor `HTTPS_PROXY` natively; Node 22 and earlier need `setGlobalDispatcher(new ProxyAgent(process.env.HTTPS_PROXY))` from undici at startup. Direct outbound is blocked by design, so `ENETUNREACH` on `1.1.1.1:443` means the runtime isn't using the proxy. Full guide: https://percher.app/docs/env-vars ## Password protection Password-protect your site so only people with the password can access it. Visitors see a branded login page, not a browser popup. ```sh # 1. Enable in percher.toml [web] port = 3000 password = true # 2. Set the password bunx percher env set SITE_PASSWORD=your-secret-here # 3. Deploy bunx percher publish ``` Available on all plans at no extra cost. A correct password sets a 7-day cookie, so visitors aren't asked again until it expires. Full guide: https://percher.app/docs/password-protection ## percher.toml — full reference Validation is strict: unknown keys in any section fail the parse instead of being silently dropped. Run `percher doctor` to surface validation issues before you publish. ```toml [app] name = "my-app" # 3-40 chars, lowercase a-z 0-9 and hyphens runtime = "node" # node | bun | python | static | docker framework = "nextjs" # optional: nextjs, sveltekit, astro, remix, nuxt, # vite, express, fastify, hono, elysia, fastapi, # flask, django, docker [build] command = "bun run build" # optional output = ".next" # optional pass_env = ["NEXT_PUBLIC_API_URL"] # opt-in build-time env; values come # from "percher env set", not the TOML [web] port = 3000 # 1024-65535 health = "/health" # default "/" password = true # optional: gate via the SITE_PASSWORD env var [resources] # recommended sizing, not a pool charge — see note below memory = "512mb" # 256mb | 512mb | 1gb | 2gb cpu = 0.5 # 0.25 - 2.0 instances = 2 # static N containers; plan-gated # (free=1, starter=1, maker=2, pro=4) [resources.autoscale] # alternative to instances; CPU-based min = 1 max = 4 [data] mode = "pocketbase" # pocketbase | postgres | sqlite | convex | # supabase | external | none [domain] custom = "myapp.com" # custom domain (requires DNS setup) [env] STRIPE_KEY = "sk_live_..." # legacy KEY=VALUE shape (still supported); or use # required/optional/ignore arrays (the env contract) [crons] cleanup = { schedule = "0 3 * * *", command = "node cleanup.js" } [dev] ignore = ["*.log", "tmp/"] debounce = 300 # ms before rebuild (100-10000) ``` **Pools are measured, not reserved (with caveats).** `[resources]` `memory` and `cpu` are *recommended sizing* — the per-container cap your app runs inside — not a standing reservation. In steady state your account pool (memory / CPU / disk) is charged on *measured* usage, so running apps occupy only what they actually use and a light idle app barely touches the pool; that's what lets you run many small apps or one heavy one. The cap isn't entirely free, though: when an app is *deployed, woken, or resized*, its requested cap is counted against the pool for that admission check, an app with no fresh sample (new/stale/mid-restart) falls back to its cap until measured again, and RAM caps are bounded by a hard 2× pool committed guard. Pick a cap that fits the app's real footprint (too low risks OOM-kill; much higher than needed only tightens deploy/wake/resize admission + the 2× RAM guard), then watch measured usage per app on its Resources tab and account-wide on the Account page. Full reference: https://percher.app/docs/percher-toml ## Deploy history and retention Every deploy is tracked with full metadata (status, timestamp, build log, error message). How many deploys you can roll back to, and how long build/runtime logs are kept, depends on your plan. Older deploys keep their history, but their Docker images and tarballs are cleaned up automatically to save disk. | Plan | Rollback deploys | Build logs | Runtime logs | |------|------------------|------------|--------------| | Free | 5 most recent | 3 days | 24 hours | | Starter | 15 most recent | 14 days | 7 days | | Maker | 30 most recent | 30 days | 30 days | | Pro | 60 most recent | 90 days | 90 days | Full guide: https://percher.app/docs/retention ## Telemetry The Percher CLI sends anonymous usage statistics to help improve the platform: CLI version, command name, success/error, OS, and Bun version. No personal data, file names, source code, or env vars are ever collected. Opt out with an environment variable: ```sh PERCHER_NO_TELEMETRY=1 # or DO_NOT_TRACK=1 ``` See the Privacy Policy at https://percher.app/privacy for full details. Full guide: https://percher.app/docs/telemetry ## Versions and rollback Every deploy is stored as a git commit in Percher's internal Forgejo instance. List versions and roll back to any previous deploy: ```sh # List all versions bunx percher versions # e950cff deploy: dep_850j... 2026-04-16 # 867d57f Initial commit 2026-04-16 # Roll back bunx percher rollback e950cff ``` Rollback redeploys the exact code from that version through the same build pipeline. You can also roll back from the Versions tab in the dashboard. Full guide: https://percher.app/docs/versions ## Zero-downtime deploys Every live deploy goes through a drain-and-swap sequence: the new container starts, passes its health check, takes over traffic via an atomic Caddy route swap, and only then is the old container stopped (after a 5-second drain window so in-flight requests finish cleanly). A 30-second canary monitor probes the new version after the swap. If two probes return 5xx in a row, Percher automatically rolls back: it restores the previous upstream, stops the failed container, and marks the deploy failed. The dashboard shows this as a stepper (Build, Start, Health check, Swap, Canary, Live) with a "Rolled back" row if the canary fired. Opt out per instance with `PERCHER_CANARY_AUTO_ROLLBACK=false`. Tune the windows with `PERCHER_CANARY_WINDOW_MS` and `PERCHER_DRAIN_GRACE_MS`. Full guide: https://percher.app/docs/graceful-deploys ## Troubleshooting common errors Fixes for the errors you're most likely to hit running `bunx percher publish`. Error names match what the CLI and dashboard show, so you can search them verbatim. `percher doctor` diagnoses most of these and prints the next action. Configuration: - **name already taken**: app names are global (they become `name.percher.run`); pick a unique `app.name`. - **unknown runtime**: `runtime` must be node | bun | python | static | docker. - **port out of range**: `web.port` must be 1024–65535 (containers don't run as root). - **repo size exceeded**: tarball over 500 MB, usually node_modules/.next/dist/.git. Check with `bunx percher publish --dry-run`; Percher honors .gitignore plus a default exclude list. Build and startup: - **build failed**: build command exited non-zero. See the log with `bunx percher logs --build`. Common causes: missing dev dependency, prod-only TS error, undeclared build env. - **health check failed**: first visit `https://your-app.percher.run/health`; if it's 200 the pipeline hit a transient blip (old version still served) so update the CLI (`bunx percher@latest publish`). If genuinely down, verify the app listens on `[web].port`, the endpoint returns 200, and `[web].health` matches your route. - **missing API key**: set the runtime env var (use `--from-file`/`--from-stdin`/interactive for secrets), then re-publish. Rate limits and quotas: - **DAILY_QUOTA_EXCEEDED (429)**: per-day cap (Free 50 live + 25 preview, Starter 100/50, Maker 200/100, Pro 1000/500), resets 00:00 UTC (`resetAt` in the response). Live and preview counters are independent, so `--preview` still works. - **DEPLOY_RATE_LIMITED (429)**: per-app 60s burst limit; retryable after `retryAfterSec`. - **RETRY_LIMIT_REACHED**: transient infra retries exhausted; try again in a few minutes or email support@percher.app. - **already_in_progress**: a deploy for this app is still running; wait or cancel it (the response includes its id). Env contract (catches missing env at upload time): declare `[env].required`/`optional`/`ignore`. **REQUIRED_ENV_MISSING** = a required key isn't set (set it, re-publish). **ENV_KEY_UNDECLARED** = source references a key not in any list (add it to one). Performance and freshness: - **Slow first paint (7+ s)**: almost always third-party fonts (fonts.googleapis.com) hanging the first paint; the request goes browser to Google, not through Percher, so self-host fonts (next/font, @fontsource, or @font-face). A stale service worker can cache the slow state; hard-reload twice. - **Changes aren't showing**: the build cache hit (keyed on a content hash of toml + package.json + lockfile + Dockerfile + build env + every source file). Force a fresh build with `bunx percher publish --no-cache`. If still stale, run publish from the project root and check .gitignore isn't excluding the changed files. Still stuck? Email support@percher.app with the deploy id and build log. Full guide: https://percher.app/docs/troubleshooting ## Custom domains Every app gets a `name.percher.run` subdomain. You can also add your own domain. ```sh bunx percher domains add myapp.com # Percher returns DNS instructions: # 1. TXT _percher-challenge.myapp.com -> percher-domain-verification= # 2. CNAME myapp.com -> your-app.percher.run bunx percher domains verify myapp.com # after DNS propagation ``` SSL is provisioned automatically via Let's Encrypt once verification passes. Full guide: https://percher.app/docs/custom-domains ## Publishing to the App Store & Google Play **Can I publish my Percher app to the Apple App Store or Google Play?** Not directly — and that's by design. Percher doesn't submit apps to the stores for you. What it does is host your app on the web — and, once you add a web manifest and a service worker, as an installable PWA (Path 0 below), so the simplest option needs no store at all: users add it to their home screen, offline-ready. But you *can* take a Percher-hosted app into the stores — keep Percher as the web + backend layer and put a thin store app on top. There are three common paths, all built on top of the PWA step. External facts below (fees, review rules) are moving targets — each is sourced and datestamped; re-check the official link before you rely on it. ## Path 0 — Just make it a great PWA (start here, no store needed) Add a web manifest and a service worker so your Percher-hosted app is installable to the phone home screen and works offline. For many apps this is the whole answer — no developer account, no store review, no fee. Everything below is optional and builds on this. Link a manifest from your HTML and serve it from your app's origin: ```html ``` `manifest.json` (starter): ```json { "name": "My App", "short_name": "MyApp", "start_url": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#2d6a4f", "icons": [ { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" } ] } ``` Register a service worker so the app is installable and works offline: ```js if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js"); } ``` This works on the shared `name.percher.run` subdomain or a custom domain. ## Path A — PWA to Google Play (TWA) Wrap an installable PWA in a Trusted Web Activity (TWA) to get a real Android app (`.aab`) you can list on Google Play. It's the cheapest store path — you reuse the PWA from Path 0. Android only: Apple doesn't support TWA. Generate the Android project with Bubblewrap, pointed at your manifest: ```sh npx @bubblewrap/cli init --manifest https://your-app.percher.run/manifest.json npx @bubblewrap/cli build ``` Or use PWABuilder (https://www.pwabuilder.com/) — paste your app URL and it produces the Android package. A TWA needs Digital Asset Links to verify you own the origin (and to hide the browser URL bar). Serve `/.well-known/assetlinks.json` on your app's origin: ```json [{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "app.percher.yourapp", "sha256_cert_fingerprints": [""] } }] ``` Fill in `package_name` and the SHA-256 fingerprint after you create and sign the Android app — they don't exist until then. Add the file to your app's own static output. ## Path B — Webview wrapper (Capacitor) to both stores Wrap your web frontend in a native shell that loads your Percher app (or bundles the frontend and calls Percher as an API) and adds native plugins. One codebase, both stores. ⚠️ Apple App Review Guideline 4.2 (minimum functionality): a bare webview wrapper is frequently rejected. Add genuine native value — push notifications, camera, offline support, native navigation — not just a website in an app shell. Set up Capacitor: ```sh npm install @capacitor/core @capacitor/cli npx cap init ``` `capacitor.config.ts` (point at your Percher app): ```ts import type { CapacitorConfig } from "@capacitor/cli"; const config: CapacitorConfig = { appId: "app.percher.yourapp", appName: "My App", webDir: "dist", server: { url: "https://your-app.percher.run", cleartext: false }, }; export default config; ``` Then add platforms: `npx cap add ios` and `npx cap add android`. ## Path C — Native frontend, Percher backend Build a real native app (React Native, Flutter, Swift, or Kotlin) that only talks HTTPS to your Percher app as its API/PocketBase backend. It's the most work but the cleanest path through Apple review — and it's Percher's sweet spot: backend-as-a-service for your store app. ```ts const API_BASE = "https://your-app.percher.run"; // PocketBase apps: use POCKETBASE_PUBLIC_URL from the app's env ``` Your data model, auth, and file storage stay in PocketBase exactly as on the web. For iOS universal links, serve `/.well-known/apple-app-site-association` (a JSON file, no extension, served as `application/json`) on your origin: ```json { "applinks": { "apps": [], "details": [{ "appID": "TEAMID.app.percher.yourapp", "paths": ["*"] }] } } ``` ## Which path? | What you have / want | Start here | Why | |---|---|---| | A web app you just want on phones | Path 0 (PWA) | installable + offline, no store, no fees | | It on Google Play, as cheaply as possible | Path A (TWA) | reuse the PWA, one `.aab` | | Both stores with some native features | Path B (Capacitor) | one codebase — mind Guideline 4.2 | | The cleanest App Store experience | Path C (native) | best review path; Percher stays the backend | ## What stays on Percher Whichever path you pick, your web frontend, API, PocketBase (database, auth, file storage), env vars, custom domain, and SSL stay on Percher, unchanged. The store app is a thin layer on top; Percher remains the web and backend layer. ## Before you start (sourced, checked 2026-06-16) - Apple Developer Program: $99/year. https://developer.apple.com/programs/ - Google Play Console: one-time $25 registration fee. https://support.google.com/googleplay/android-developer/answer/6112435 - Apple App Review Guideline 4.2 (minimum functionality) — bare webview wrappers get rejected; add native value. https://developer.apple.com/app-store/review/guidelines/ - A custom domain is strongly recommended: you own and control the origin for Digital Asset Links and universal links. Run `bunx percher domains add` (auto-SSL included). The shared `name.percher.run` subdomain still works. - Signing, store listings, and review are your responsibility. Percher hosts the web + backend layer; it does not submit apps to the stores on your behalf. Full guide: https://percher.app/docs/app-stores ## Persistent app data Each app has a persistent `/app/data` directory backed by a Docker volume. Data there survives container restarts and redeploys. Use it for SQLite databases, uploaded files, caches, or any state your app needs to keep. The volume is deleted when the app is deleted. See Backup and restore (https://percher.app/docs/backup-and-restore) for how the platform protects it. Full guide: https://percher.app/docs/persistent-data ## Deploy instruction for AI agents Add this context to your project's `CLAUDE.md`, Cursor rules, or paste it when starting a project, so your AI assistant builds the app to deploy correctly on Percher. Requirements: the app must expose an HTTP server on a configurable port (default 3000) and a health endpoint that returns 200 (usually `GET /health`); a `percher.toml` must exist in the project root. Node/Bun build through Percher's multi-stage Dockerfile; Python and others auto-detect via Nixpacks; `runtime = "docker"` uses your own Dockerfile. runtime is one of node, bun, python, static, docker (use docker for Go, Rust, PHP, Ruby, Java, .NET, Elixir). How to deploy: `bunx percher publish` or the `percher_publish` MCP tool handles auth, config, packaging, and deploy in one call and returns structured errors. The agentic happy path (MCP) is: ``` publish (waitForLive: false) -> wait_for_deploy -> if recovery says so: doctor -> exact action ``` `percher_publish` returns in seconds with `status: "queued"` and a `deployId`; `percher_wait_for_deploy` (args pre-filled in `recovery.args`) reports live/failed/replaced; ambiguous failures route to `percher_doctor`, the recovery hub. Agent recovery contract: every MCP tool that can fail returns `recovery.nextAction`, one of: none, open_login, wait_deploy, run_doctor, set_env_vars, fix_problems, retry, fix_config, ask_user, inspect_build_log. Read `recovery.nextAction` (don't regex the suggestion text), call exactly the suggested tool with exactly `recovery.args` (keep `mode`/`deployId`), and repeat until it's `none` (success) or `ask_user`. Database: add `[data] mode = "pocketbase"` for a managed PocketBase (connect via `POCKETBASE_URL`). Env: set with `bunx percher env set KEY=VALUE` or `percher_env_set`; declare a `[env]` contract (required/optional/ignore) so undeclared keys block the deploy with `fix_config` instead of failing mid-build. Apps deploy to https://.percher.run with automatic SSL. Full guide: https://percher.app/docs/ai-agents ## MCP tools for AI assistants Percher ships an MCP (Model Context Protocol) server so AI assistants like Claude Code, Cursor, and Windsurf can deploy and manage apps directly. Run `bunx percher mcp` to print the config, or add it manually: ```json // Claude Code: ~/.claude/mcp.json · Cursor: .cursor/mcp.json { "mcpServers": { "percher": { "command": "npx", "args": ["-y", "@percher/mcp"] } } } ``` All 49 tools, by area. Several families are single tools with an `action` parameter (e.g. `percher_domain { action: "add" | "verify" | "list" | "remove" }`). Deploy & recovery: `percher_publish` (primary; MCP defaults waitForLive=false, returns a queued deployId), `percher_wait_for_deploy`, `percher_wait_for_auth`, `percher_init`, `percher_login`, `percher_redeploy`, `percher_reproduce`, `percher_rollback`, `percher_versions`, `percher_cache_reset`, `percher_doctor` (recovery hub), `percher_unsuspend`. Inspect & discover: `percher_deploys`, `percher_deploys_inspect` (or latestFailed), `percher_logs`, `percher_app_insights` (idle / memory-pressure / overprovisioned / deploy-regression), `percher_app_topology`, `percher_app_resources`, `percher_capabilities`, `percher_inspect_link`, `percher_whoami`, `percher_open`. Env: `percher_env_set`, `percher_env_unset`, `percher_env_list` (masked). Data: `percher_data`, `percher_data_export`, `percher_export`, `percher_reset_superuser`, `percher_backups`, `percher_restore` (per-app + per-component, supports dryRun). Domains: `percher_domain { action: add | verify | list | remove }`. Git auto-deploy & previews: `percher_github { action: connect | setup_webhook }`, `percher_forgejo { action: connect | setup_webhook }`, `percher_set_preview_branch`. Webhooks (account-level, one URL per user): `percher_webhook { action: add | list | remove }` — add returns signingSecret once. Collaborators & transfer: `percher_share { action: list | invite | set_role | revoke }`, `percher_invites { action: list | accept | decline }`; ownership `percher_transfer { action: initiate | cancel | list }`, `percher_transfers { action: incoming | accept | decline }`. Migrate & import: `percher_import` (Vercel/Netlify), `percher_supabase { action: inspect | migrate_schema }`. App lifecycle: `percher_create_from_template` (29 starters), `percher_claim_app`, `percher_rename`, `percher_delete_app` (requires confirm: true). Account: `percher_account_deletion_preview`, `percher_account_delete` (preview-gated, fail-closed). Billing: `percher_billing { action: upgrade | portal }`. Full reference: https://percher.app/docs/mcp-tools ## Crash diagnostics Opt-in per app. AI-powered crash analysis is off by default; turn it on in app settings (Crash diagnostics, Enable) to start receiving banners. The crash watchdog always runs; only the AI explanation step is gated by the opt-in. Once enabled, a crash makes Percher collect logs, redact secrets, and run AI analysis (Anthropic Claude primary, OpenRouter fallback) to explain what went wrong. Reports appear as a banner on the app's dashboard page with a copy-paste fix prompt you can hand to your AI assistant. The watchdog monitors Docker container events in real time: a non-zero exit queues an analysis within seconds, and OOM kills (exit code 137) are flagged automatically with memory-limit suggestions. For AI assistants with MCP: call `percher_doctor` with `mode="runtime"` to fetch the latest crash report in chat. The response's `recovery.prompt` carries the AI explanation, suggested fix, and log tail. Doctor is the single recovery hub on the MCP surface. Stale reports (over 24h old) on apps that have recovered are filtered out. Full guide: https://percher.app/docs/crash-diagnostics ## Monitoring & alerts Percher pings every paid app from outside the cluster on a schedule and tells you when external probes start failing. This is distinct from crash diagnostics: the watchdog watches the container process, while uptime monitoring watches whether the app is reachable from the internet (DNS, Caddy, TLS, 5xx). Both can fire for the same incident. Probe cadence per plan: Free disabled, Starter every 5 minutes, Maker every minute, Pro every 30 seconds. The probe fetches the app's primary URL (verified custom domain if any, else the `*.percher.run` subdomain) with an 8-second timeout; HEAD falls back to GET for hosts that 405 on HEAD. 2xx/3xx counts as up; 4xx, 5xx, and network errors count as down. Outage detection: a single bad probe is not an outage. Three consecutive failures flip the app to down and fire `app.unhealthy`; a later success flips it back and fires `app.recovered` (only when the matching unhealthy was actually delivered). A 15-minute cooldown gates re-firing during flapping. The Health tab shows live status, 24h/7d/30d uptime %, a latency sparkline, and a 7-day outage log. Per-route 5xx tracking: the Analytics tab's Top error paths panel shows which routes returned 4xx/5xx, sorted by 5xx count with errorRate% per route. Aggregated daily from Caddy access logs and re-summed across the selected window, so a consistently-failing route rises to the top of the 30-day view even if it's never the worst on a single day. Updates every 15 minutes. Full guide: https://percher.app/docs/monitoring ## Cost optimization insights Every app has a Suggestions card on its overview tab listing cost-optimization and reliability ideas computed from traffic, crash, and deploy history. Four rule kinds: - **idle**: zero requests and visitors in 30 days (app at least 14 days old). Consider deleting. - **memory-pressure**: 2+ OOM kills in 14 days. Upgrade the plan or reduce memory use. - **overprovisioned**: on maker/pro with under 100 req/day averaged over 14 days and no OOMs. Consider downgrading. - **deploy-regression**: 3+ failed deploys in 24h. Something changed; review the latest build log. Each suggestion has a one-click action button in the dashboard (Manage subscription, Upgrade to maker, View crash details), so non-MCP users get the same shortcut an AI assistant does. For AI assistants, `percher_app_insights` returns the same structured suggestions with a machine-readable `actionHint` naming the follow-up tool and action (`percher_billing` with action portal or upgrade, etc.). Full guide: https://percher.app/docs/cost-insights ## Multi-instance & auto-scaling Run multiple containers behind a single Caddy load balancer with active health checks. Two ways to configure it in percher.toml. Static fan-out: ```toml [resources] instances = 2 # runs 2 containers, load-balanced ``` Plan caps: free=1, starter=1, maker=2, pro=4. Exceeding the cap is silently clamped with a note in the build log. CPU-based autoscaling: ```toml [resources.autoscale] min = 1 max = 4 ``` Percher samples CPU every 30s, evaluates every 50s, and scales by ±1 when the sustained average crosses the threshold (default: up at over 80% for 2 min, down at under 20% for 10 min). Scale-up is conservative (one instance per action) and a cooldown prevents thrashing. Active Caddy health checks route traffic around any unhealthy instance. A single-instance crash in a multi-instance deploy stays at severity "warning" (the app keeps serving); the app only becomes "crashed" when all instances are down at once. Per-deploy scale history lives on the deploy detail card. Full guide: https://percher.app/docs/multi-instance ## Event webhooks Percher POSTs signed JSON payloads to your webhook URL when events happen: useful for Discord/Slack bots, on-call pagers, or custom dashboards. Account-level: one URL per user, all events go there. Events: - `deploy.succeeded`: a deploy reached live (data: deployId, url, durationMs, kind "live"|"preview"). For "live" it fires only after the post-swap canary closes cleanly, so it's never contradicted by a deploy.failed for the same deployId. `url` is always the `.percher.run` domain; custom domains are looked up separately. - `deploy.failed`: any deploy fails (build, health, or canary). - `app.crashed`: the watchdog detects a process exit or OOM. - `app.unhealthy`: external uptime probe failed 3 times in a row (Starter and up). - `app.recovered`: app responds again after an unhealthy window (pairs with a delivered unhealthy event). - `domain.expiring`: a custom-domain SSL cert is within 7 days of expiry. - `security.finding`: a security scan first finds a fixable/exploitable vulnerability in a live app (data: tier "yellow"|"red", findings[] with cve, component, severity, fixedIn, tier, deadlineAt). Fires once per finding when it crosses the threshold, not on every re-scan. `app.crashed` is container-level (process exited); `app.unhealthy` is reachability (DNS/Caddy/TLS/5xx). They're independent and both can fire for one incident. `app.unhealthy` has a 15-minute cooldown to avoid pager spam. Setup: Settings, Notifications, paste your receiver URL. A signing secret is shown once; copy it into your receiver's `PERCHER_WEBHOOK_SECRET`. Changing the URL rotates the secret; clearing it clears the secret. Verify signatures: every delivery carries `X-Percher-Signature: sha256=`, an HMAC-SHA256 of `${timestamp}.${body}`. Reject anything older than a few minutes for replay protection. ```js import { createHmac, timingSafeEqual } from "node:crypto"; function verify(secret, req, body) { const sig = req.headers.get("X-Percher-Signature") ?? ""; const ts = req.headers.get("X-Percher-Timestamp") ?? ""; const expected = createHmac("sha256", secret).update(`${ts}.${body}`).digest("hex"); const provided = sig.replace(/^sha256=/, ""); if (expected.length !== provided.length) return false; return timingSafeEqual(Buffer.from(expected), Buffer.from(provided)); } ``` Deliveries are best-effort with a 5-second timeout; 5xx responses are logged but not retried, so queue events in your receiver if you need retries or ordering. Full guide: https://percher.app/docs/webhooks ## Security scanning Percher scans every image it builds for known vulnerabilities (CVEs) and keeps watching your live apps after they ship, so a CVE disclosed next week still reaches you. Findings live in your app's Security tab, sorted by how much they matter: - Red: a critical vulnerability that has a fix available and is reachable from the internet. Worth handling soon. - Yellow: a fixable issue that isn't critical or isn't internet-reachable. Update when you're ready. - Green: informational, or no fix released yet. Nothing to do. Each finding names the CVE, the affected component, and where it lives in your image (for example the exact binary or node_modules path), so you can tell at a glance whether it's your dependency or a build tool you can drop. A common surprise: a "stdlib" finding is usually a Go binary like esbuild bundled into node_modules by your toolchain, not a server component. Percher only emails you about red findings, the ones genuinely worth acting on. Lower-severity findings stay in the dashboard, not your inbox. The email includes the fix version and a ready-to-paste prompt for your AI assistant so the upgrade and redeploy are one step. CVEs in the base image and language runtime Percher chose for you are handled centrally by Percher. They're never counted against your app, never block your deploy, and never land in your inbox. To clear a finding: upgrade the affected dependency and redeploy. The next scan confirms it's gone and the finding resolves automatically. Full guide: https://percher.app/docs/security-scanning ## PocketBase — database, auth & files PocketBase is a managed SQLite-backed backend that gives you a REST API, user auth, file storage, and realtime subscriptions in one. It runs as a sidecar container alongside your app. Setup is one line in percher.toml: ```toml [data] mode = "pocketbase" ``` Three env vars are injected automatically: `POCKETBASE_URL` (internal Docker URL for server-side calls), `POCKETBASE_PUBLIC_URL` (public URL with SSL), and `VITE_POCKETBASE_URL` (public URL, Vite convention). Connect with the official SDK: ```js import PocketBase from "pocketbase"; const pb = new PocketBase(process.env.POCKETBASE_URL); // server-side const pb = new PocketBase(import.meta.env.VITE_POCKETBASE_URL); // browser ``` The SDK covers CRUD (`pb.collection("tasks").create/getList/update/delete`), auth (`authWithPassword`, `pb.authStore`), file uploads via FormData + `pb.files.getURL`, and realtime (`pb.collection("messages").subscribe`). Admin UI is at `pb-yourapp.percher.run/_/` (create collections, set API rules, manage data); the admin password is shown once after the first deploy. Rotate it with `bunx percher data reset-superuser ` (re-injects `POCKETBASE_ADMIN_PASSWORD` encrypted; add `--reveal` to print it once, then redeploy). Don't use PocketBase's "forgot password" flow for superuser recovery; it needs SMTP, which isn't configured by default. Email (SMTP) is bring-your-own: Percher doesn't provide SMTP for the sidecar, so every PB feature that sends mail (signup verification, password reset, OAuth notifications) is a silent no-op until you configure a provider in the PB admin UI under Settings, Mail settings (Resend, Postmark, SES, Mailgun, SendGrid, or your own). Until then PocketBase's password-reset endpoint still returns HTTP 204 even though no mail leaves the box. Full guide: https://percher.app/docs/pocketbase ## Export PocketBase data Export your PocketBase database and uploaded files as a `.tar.gz` archive, for local development, migrating to another app, or your own off-device backup. Trigger it from the dashboard (Data tab, Export data) or the CLI: ```sh bunx percher data export # app name from percher.toml bunx percher data export my-app # explicit app bunx percher data export --out backup.tar.gz # custom output path ``` The file streams straight to disk (never fully buffered), so it works at any size. The archive is a snapshot of the sidecar's `pb_data` directory: `data.db` (SQLite, all collections and rows), `data.db-wal` (if non-empty), `storage/` (uploaded files), and `pb_migrations/`. PocketBase writes the WAL out atomically, so the exported `data.db` is always consistent. Browse it locally with `sqlite3 pb_data/data.db`, or run a local PocketBase against it: `./pocketbase serve --dir pb_data` then open `http://127.0.0.1:8090/_/`. Importing into a new Percher app: the export is a raw `pb_data/` snapshot, not a native PocketBase backup ZIP, so it can't be uploaded directly via the PB backup UI. Either (A) run PocketBase locally on the extracted data, create a native backup (Admin UI, Settings, Backups), and upload that ZIP to the new app's PB admin UI; or (B) email support@percher.app with source and target app names and we copy the `pb_data` volume between containers. Export rate limits per app per 24h: Free 1, Starter 1, Maker 2, Pro 5, Enterprise 50. Per app, not per account; each attempt counts even if the download is cancelled. Full guide: https://percher.app/docs/export-data ## Backup & restore Percher backs up the entire platform every night to encrypted off-site storage, so a corrupted database, deleted volume, or lost server restores from yesterday's archive rather than from scratch. What's backed up: every app's `/app/data` volume (databases, uploaded files, SQLite, caches), every PocketBase sidecar's `pb_data`, platform metadata (apps, users, deployments, env-var ciphertext, custom-domain config), Forgejo deploy-history repositories, and Caddy TLS certs (so HTTPS works immediately after a restore). Schedule and storage: daily at 02:00 UTC, encrypted with AES-256 (GPG symmetric, passphrase held only off-server), uploaded to off-site storage in a different EU datacenter from production. Retention is 30 days local and 30 days off-site. A failed backup pings on-call on Discord and emails info@percher.app within minutes. Requesting a restore: email support@percher.app with the app name, what was lost, and the approximate incident time. Restores are operator-mediated today (no self-service button yet); same-day turnaround on paid plans. What it does not protect against: writes between 02:00 UTC and the failure (up to ~24h of data), application-level corruption you replicated into a backup, and loss older than the 30-day retention window. Note: `bunx percher delete` removes the app immediately, but the previous night's archive still has its metadata and data volume, so an accidental delete can usually be recovered within the 30-day window. For sub-daily protection, run your own dump (PocketBase's built-in backup endpoint, or copy your SQLite file out of `/app/data` on a schedule). Full guide: https://percher.app/docs/backup-and-restore ## Billing & plans Plan changes go through Polar. Three ways to change your subscription: - **Dashboard**: Settings, Plan. Upgrade opens a Polar checkout; existing subscribers get a Manage subscription button that opens the Polar customer portal. - **AI assistant (MCP)**: `percher_billing(action: "upgrade", plan)` returns a checkout URL, `percher_billing(action: "portal")` returns the portal URL. The assistant surfaces the URL; you click to confirm. - **Suggestions**: when insights detect overprovisioning, the Manage subscription action on the overview tab takes you to the Polar portal. Percher never changes subscriptions server-side. Every path ends with you confirming in the browser. Once Polar reports the new status via webhook, your plan limits update automatically, with no redeploy. Full guide: https://percher.app/docs/billing ## Migrating from Supabase Two options: keep your Supabase project as an external database, or switch to Percher's managed PocketBase. For most apps — and anything that leans on Postgres features — Option 1 is the right call. Option 1, keep Supabase (recommended, no rewrite): ```toml [data] mode = "supabase" [data.supabase] url = "https://your-project.supabase.co" anon_key = "eyJ..." ``` No code changes; `SUPABASE_URL` and `VITE_SUPABASE_URL` are injected and your existing client keeps working. This works for every Supabase app — you keep Postgres, RLS, auth, storage, edge functions, realtime, and pgvector exactly as they are. Percher just hosts the app. Option 2, switch to PocketBase. Percher generates most of the migration for you: ```sh bunx percher migrate-from-supabase --project --token sbp_... ``` This writes a `./migration-preview/` folder (nothing touches your data yet): - `pb_schema.json` — your tables mapped to PocketBase collections - `pb_migrate.js` — a runnable data-import script that copies your rows over - `MIGRATION_NOTES.md` — every RLS policy, flagged column, and manual step Add `--rewrite-client` to also convert your Supabase SDK calls to the PocketBase SDK across the project (preview first; `--apply` writes in place and backs up the originals). Honest limits — read before committing: - Auth users can't be moved directly. Supabase password hashes aren't compatible with PocketBase, so every user has to reset their password. - It's a preview plus a script, not one click. You run the data-import yourself with a Supabase service-role key and review the flagged items. - Not portable: Edge Functions (use API routes), Postgres views/triggers/functions (rewrite as app logic), complex RLS (PocketBase API rules use a different model — the tool translates the simple `auth.uid() = column` case and flags the rest), realtime, PostGIS, and Supabase Vector/embeddings (use an external service). If your app depends on those Postgres features, keep Supabase (Option 1). Concept mapping for the parts you rewrite by hand: - `supabase.from('t').select()` -> `pb.collection('t').getList()` - `.insert({})` / `.update({})` / `.delete()` -> `.create({})` / `.update(id, {})` / `.delete(id)` - `supabase.auth.signUp()` -> `pb.collection('users').create({})` - `signInWithPassword()` -> `pb.collection('users').authWithPassword()` - `auth.getUser()` -> `pb.authStore.record` - `storage.upload()` -> `pb.collection('x').create(formData)` - `channel().subscribe()` -> `pb.collection('x').subscribe('*', fn)` - Row Level Security -> PocketBase API rules (per collection) - `.select('*, posts(*)')` -> `pb.getList({ expand: 'posts' })` Not portable: Edge Functions (use API routes), Postgres views/triggers (rewrite as app logic), PostGIS (unavailable), Supabase Vector/embeddings (use an external service). Full guide: https://percher.app/docs/migrate-supabase ## Migrating from Convex Two options: keep your Convex deployment, or switch to Percher's managed PocketBase. Option 1, keep Convex (easiest): ```toml [data] mode = "convex" [data.convex] deployment_url = "https://your-project.convex.cloud" ``` `CONVEX_URL` and `VITE_CONVEX_URL` are injected; your existing client, queries, and mutations keep working. Option 2, switch to PocketBase. Concept mapping: - `useQuery(api.tasks.list)` -> `pb.collection('tasks').getList()` - `useMutation(api.tasks.create)` -> `pb.collection('tasks').create({})` - Convex schema (schema.ts) -> PocketBase collections (admin UI or API) - Convex functions (convex/) -> API routes in your app - Convex auth (Clerk/Auth0) -> PocketBase built-in auth - Convex file storage -> PocketBase file fields - Realtime (automatic) -> `pb.collection('x').subscribe('*', fn)` Key difference: Convex runs server functions in their cloud. With PocketBase your API routes run in your app container, so move Convex functions to Express/Hono/Next.js API routes. Full guide: https://percher.app/docs/migrate-convex ## Migrating from Vercel Most Vercel projects deploy on Percher with minimal changes. Works out of the box: Next.js (Pages and App Router), SvelteKit, Remix, Nuxt, Astro, static sites (Vite/React/Vue), API routes (Express/Hono/Fastify), environment variables, and custom domains. Needs changes: - Vercel Serverless Functions -> run as a normal Node server (Express/Hono), no cold starts - Vercel Edge Functions -> not supported; use standard API routes - Vercel KV / Postgres / Blob -> PocketBase (`mode = "pocketbase"`) or an external service - `vercel.json` rewrites/redirects -> handle in app code or framework config - Vercel Cron Jobs -> `[crons]` in percher.toml - Vercel Analytics -> a third-party analytics service - ISR / on-demand revalidation -> works; Next.js ISR runs in the container Steps: ```sh cd my-vercel-app bunx percher init # auto-detects Next.js/SvelteKit/etc. # add a health endpoint if missing, e.g. Next.js app/api/health/route.ts bunx percher env set DATABASE_URL=... bunx percher publish bunx percher domains add myapp.com ``` Full guide: https://percher.app/docs/migrate-vercel ## Migrating from Lovable Build in Lovable, host on Percher. Lovable turns a chat into a working Vite + React + Supabase project; Percher gives it a live URL on your own domain with flat-rate hosting. The two layers stay independent — keep iterating in Lovable, redeploy to Percher when you hit a milestone. What carries over (without changes): - Your code — Lovable syncs the project to GitHub as a standard Vite + React app, no proprietary format. - Your Supabase backend — database schema, RLS policies, auth providers, and edge functions stay unchanged. Point Percher at the same project via env vars. - Your Lovable workflow — keep using the chat to iterate; sync to GitHub and `bunx percher publish` picks up the new state. - Existing user accounts — Supabase auth users stay in the same database. Only the React bundle moves. Steps: ```sh # 1. In Lovable: sync your project to GitHub # 2. Clone it locally git clone https://github.com/you/your-lovable-project cd your-lovable-project # 3. Generate percher.toml (init detects Vite + scaffolds Dockerfile + Caddyfile) bunx percher init # 4. Re-set your Supabase env vars (the VITE_ prefix auto-forwards to the build) bunx percher env set VITE_SUPABASE_URL=https://xxx.supabase.co bunx percher env set VITE_SUPABASE_ANON_KEY=eyJhbGc... # 5. Build and deploy bunx percher publish # 6. Custom domain (one DNS update — the CLI prints the records) bunx percher domains add yourdomain.com ``` The Vite project ships as `runtime = "docker"` with a multi-stage build: a slim Bun image compiles the bundle, a slim Caddy image serves it (~30 MB runtime image, automatic SSL via Let's Encrypt). Supabase auth: add your Percher URL to Supabase Authentication -> URL Configuration -> Site URL and Redirect URLs, or OAuth callbacks and email confirmations come back to the old domain. What changes on Percher: - You own the URL — `name.percher.run` right away, or bring your own domain on any paid plan. - Real logs — `bunx percher logs` streams runtime logs; `bunx percher logs --build` shows any deploy's build log. - Rollback — every deploy gets a content hash and stays in history; roll back with one CLI call or one dashboard click. Data is untouched. - Flat cost — no bandwidth meter, no token meter. - EU data residency — Percher runs in a single EU region (Germany). Note: Percher is hosting for personal and small-scale apps: things you build for yourself, your family, a club or association, or a smaller business. It has no uptime SLA and no formal compliance attestation. For a monetised SaaS or anything with contractual uptime, Lovable's own production hosting or a higher-tier provider is the better fit. **Do I have to stop using Lovable?** No. Keep building in Lovable's chat, sync to GitHub at a milestone, then re-deploy with `bunx percher publish`. **What happens to my Supabase project?** Nothing. Copy `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` from Lovable and re-set them on Percher; the `VITE_` prefix bakes them into the bundle on the next deploy. **What about Supabase auth callbacks and OAuth?** Add your Percher URL to Supabase Authentication -> URL Configuration -> Site URL and Redirect URLs. **Is the migration reversible?** Yes. You keep the GitHub code and the Supabase backend; Percher is hosting with no lock-in. **Does Percher have an AI app builder like Lovable?** No. Pair Lovable (or another AI tool) for building with Percher for hosting. Full guide: https://percher.app/docs/migrate-lovable ## Percher vs Vercel Percher vs Vercel. Vercel is the production hosting platform for Next.js — fast global edge, deep Git integration, and a polished serverless runtime tuned by the team that maintains Next.js itself. Both Vercel and Percher ship MCP servers for AI assistants today; the real difference is depth. Percher is built around MCP as the primary deploy surface — 49 tools covering publish, logs, env, rollback, doctor, backups, domains and GitHub-connect, plus a typed `recovery.nextAction` contract so failed deploys chain into the next tool call automatically. Pricing is flat per account (€0 / €3 / €12 / €29) with no bandwidth meter. If you're shipping a serious Next.js app at scale with a team, Vercel is the safer bet; if you want your assistant to run the whole operational loop and the bill not to surprise you on a viral weekend, Percher is built for that workflow. Who Percher is for: Percher is for personal and small-scale apps: things you build for yourself, your family, a club or association, or a smaller business or organisation. It is not enterprise or production-grade hosting, by design, and the reasons are concrete. One region means no geographic failover, so a regional outage takes the app fully down with no automatic recovery. There is no uptime SLA, so nothing contractually guarantees it stays up or compensates you when it doesn't. And there is no SOC 2 or HIPAA attestation, so it can't clear enterprise security or compliance review. If you're running a monetised SaaS with paying customers, an app under a customer contract, or anything where downtime has financial or legal consequences, a higher-tier provider is the right call. At a glance: | Feature | Percher | Vercel | | --- | --- | --- | | Free tier | Free plan (3 apps, sleep after 20 min idle) | Hobby plan (personal projects, non-commercial) | | Paid entry price | €3/mo (Starter) — flat, per account | $20/user/mo (Pro) — as of 2026-05 | | Pricing model | Flat monthly subscription | Per-seat + usage-based (bandwidth, builds, functions) | | Bandwidth model | Unmetered within plan pool | Included quota + per-GB overage | | Region | Single EU region (Germany) | Global edge network | | Compute model | Long-running containers per app | Serverless functions + edge runtime | | Built-in database | Opt-in managed PocketBase per app (SQLite + auth + file storage) via `[data] mode = "pocketbase"` | None native — Marketplace integrations (Neon, Supabase, …) | | Built-in auth | Yes (when PocketBase is enabled) — auth out of the box with PocketBase | No — bring your own (Auth.js, Clerk, etc.) | | MCP server | MCP-first: 49 tools covering the full operational surface (publish, logs, env, rollback, doctor, backups, domains, GitHub connect) with a typed `recovery.nextAction` contract for chaining failures into fixes | Has an MCP server for deployment management (Vercel MCP) — focused on project / deployment lookup and log retrieval | | Framework support | Node, Bun, Python, static, any Dockerfile | Next.js first-class; broad framework support otherwise | | Custom domains | Yes (paid plans) | Yes | | Automatic SSL | Yes — Let's Encrypt via Caddy | Yes | | Data residency | EU only (Germany) | Global; region selection per project | | Rollback | Instant per-deploy rollback | Instant per-deploy rollback | When Percher is the better choice: - You want the assistant to do more than `publish` — full operational surface (logs, env, rollback, doctor, backups, domain add, GitHub connect) as MCP tools, plus a typed `recovery.nextAction` so a failed deploy turns into the next tool call automatically. - You want predictable flat-rate pricing without bandwidth or build-minute surprises — the same €0 / €3 / €12 / €29 every month. - You want a managed PocketBase database, auth, and file storage available with one config line (`[data] mode = "pocketbase"`), instead of stitching together Marketplace integrations. - Your project must stay in the EU for data-residency or compliance reasons. Percher's infrastructure is single-region in Germany. - You're a solo builder or small team and Vercel's per-seat Pro plan is over-spec'd for your headcount. When Vercel is the better choice: - You're building a serious Next.js app that depends on Vercel-specific features at scale: ISR with on-demand revalidation, image optimization, edge middleware, or Server Actions tuned to Vercel's runtime. - Your audience is global and edge latency matters. Percher runs in one region; Vercel's edge network has many more. - You have a team that benefits from Vercel's collaboration features — preview comments, branch protection rules, role-based access control. - You need enterprise compliance (SOC 2, HIPAA, regional data processing agreements). Percher is a young single-team project; Vercel's compliance surface is larger. - You're already invested in Vercel's data products (KV, Postgres, Blob) or its monitoring stack and don't want to migrate them. Migrating from Vercel: If your Vercel project is a Next.js, SvelteKit, Astro, Remix, or plain Vite app, the migration is mostly mechanical. Percher's CLI has an `import` command that reads `vercel.json` and generates a working `percher.toml`, then `publish` builds and deploys exactly like Vercel would. Environment variables don't migrate automatically — set them with `percher env set` (or paste them in the dashboard). Domains move once the app is live by adding the domain in Percher and updating the DNS records the CLI prints. What doesn't carry over: Vercel Edge Functions (`runtime: 'edge'` in Next.js) need to be converted back to standard Node runtime — Percher's compute is regional containers, not edge. Vercel KV, Postgres, and Blob storage have no direct equivalent. For the SQLite + auth + S3-compatible file storage shape, opt into the managed PocketBase sidecar with `[data] mode = "pocketbase"` in percher.toml — Percher provisions the sidecar on first deploy and injects `POCKETBASE_URL` automatically. For raw Postgres specifically, point `DATABASE_URL` at any external provider — Neon, Supabase, your own server. ```sh # In your project root (where vercel.json lives): bunx percher import # reads vercel.json -> percher.toml bunx percher env set DATABASE_URL=... # for each env var bunx percher publish # build + deploy bunx percher domains add yourdomain.com ``` FAQ: **Can I deploy a Next.js app to Percher?** Yes. Percher detects `next.config.js` automatically and builds with `bun run build` — no Percher-specific changes to your Next.js code. Standard features like ISR, Server Components, Server Actions, image optimization, and middleware work as written. The exceptions are Vercel Edge Functions and Vercel's own data products (KV, Postgres, Blob), which need adaptation — see the migration section above. **Is Percher cheaper than Vercel?** For predictable, low-to-moderate traffic solo projects, yes — Percher's flat plans (€0 / €3 / €12 / €29 per month) are typically cheaper than Vercel's per-seat Pro plan ($20/user/mo plus usage, as of 2026-05). For teams or apps with very bursty traffic that benefit from scale-to-zero, Vercel's serverless model can win. The honest answer is: do the math against your actual usage; both pricing pages are public and the live numbers may have shifted since this page was written. **Does Percher have an edge network like Vercel?** No. Percher runs in a single EU region (Germany). That's a deliberate trade-off — one region means much simpler infrastructure and stable pricing, but a user in São Paulo will see more latency than on Vercel's nearest edge. If your audience is mostly in Europe, the trade is fine; if it's truly global, Vercel (or putting a CDN in front of Percher) is the right call. **Can I deploy from GitHub like with Vercel?** Yes. `bunx percher github connect ` sets up a webhook so every push to your tracked branch triggers a deploy — the webhook is HMAC-signed. Only public repos are supported on the webhook path; for private repos use a Percher API token from GitHub Actions instead. Branch tracking, preview deploys, and rollback all work the same way they do on Vercel. **What about my Vercel KV / Postgres / Blob storage?** Those are Vercel-proprietary products without a 1:1 equivalent on Percher. For the SQLite + auth + S3-compatible file storage shape, opt into the managed PocketBase sidecar by adding `[data] mode = "pocketbase"` to your percher.toml — Percher provisions PocketBase alongside your app and injects `POCKETBASE_URL` automatically. For raw Postgres specifically, run any external provider (Neon, Supabase, your own) and set `DATABASE_URL` as a normal env var; Percher's outbound proxy handles the connection. ## Percher vs Render Percher vs Render. Render and Percher are architecturally close cousins: both run long-lived containers behind a managed proxy, both ship from Git, both auto-issue TLS, and both expose an MCP server today. The real differences are who they're built for and how deep the agent integration goes. Render is a polished, multi-region PaaS aimed at small-to-mid teams who want managed Postgres + Redis and per-service pricing they can scale up. Percher is a solo-builder platform with MCP as the primary deploy surface — 49 tools covering the full operational loop and a typed `recovery.nextAction` contract — opt-in PocketBase batteries (`[data] mode = "pocketbase"`), and flat per-account pricing. Who Percher is for: Percher is for personal and small-scale apps: things you build for yourself, your family, a club or association, or a smaller business or organisation. It is not enterprise or production-grade hosting, by design, and the reasons are concrete. One region means no geographic failover, so a regional outage takes the app fully down with no automatic recovery. There is no uptime SLA, so nothing contractually guarantees it stays up or compensates you when it doesn't. And there is no SOC 2 or HIPAA attestation, so it can't clear enterprise security or compliance review. If you're running a monetised SaaS with paying customers, an app under a customer contract, or anything where downtime has financial or legal consequences, a higher-tier provider is the right call. At a glance: | Feature | Percher | Render | | --- | --- | --- | | Free tier | Free plan (3 apps, sleep after 20 min idle) | Free web service tier (sleep after idle, monthly hour cap) | | Paid entry price | €3/mo (Starter) — flat, per account | Per-service pricing (Starter web service ~$7/mo) — as of 2026-05 | | Pricing model | Flat monthly subscription per account | Per-service + bandwidth + database add-ons | | Region | Single EU region (Germany) | Multi-region (US, EU, Asia, Australia) | | Compute model | Long-running containers per app | Long-running containers per service | | Built-in database | Opt-in managed PocketBase per app (SQLite, auth, file storage) via `[data] mode = "pocketbase"` | Managed Postgres + Redis (separate billed services) | | Built-in auth | Yes (when PocketBase is enabled) — auth out of the box with PocketBase | No — bring your own | | MCP server | MCP-first: 49 tools covering publish, logs, env, rollback, doctor, backups, domains and GitHub connect, plus a typed `recovery.nextAction` for chaining failures into fixes | Has an MCP server for service management (deploy lookup, log retrieval, service ops) | | Framework support | Node, Bun, Python, static, any Dockerfile | Node, Python, Ruby, Go, Elixir, Rust, any Dockerfile | | Background workers / cron | Not first-class (use a single long-running app) | First-class service types: workers, cron jobs | | Custom domains | Yes (paid plans) | Yes | | Automatic SSL | Yes — Let's Encrypt via Caddy | Yes — Let's Encrypt | | Compliance | EU data residency; no formal certifications yet | SOC 2 Type 2, HIPAA available on paid plans | | Rollback | Instant per-deploy rollback | Instant per-deploy rollback | When Percher is the better choice: - You want the assistant doing more than `publish` — full operational tools (logs, env, rollback, doctor, backups, domain add) and a typed `recovery.nextAction` that chains a failed deploy into the next fix without leaving the chat. - You want flat per-account pricing so two or three small apps don't multiply your bill — Render charges per service. - You want an opt-in managed PocketBase per app for SQLite + auth + file storage (one config line: `[data] mode = "pocketbase"`) rather than standing up a separate Postgres service and bolting on auth. - Your project needs EU data residency. Percher runs in Germany only. - You're a solo builder where the per-service cost and per-database add-on cost on Render add up faster than the value they bring. When Render is the better choice: - You need managed Postgres or Redis as a first-class product, not an external service connected over `DATABASE_URL`. Render's databases are tightly integrated with the platform. - You need multi-region deployment — US, Europe, Asia, Australia. Percher is single-region in Germany. - You need explicit background workers or cron jobs as first-class service types. Render models those distinctly; Percher doesn't. - You need SOC 2 Type 2, HIPAA, or other formal compliance certifications. Percher is a young single-team project without those yet. - You're scaling beyond a handful of apps and want fine-grained per-service control — instance types, autoscaling per service, private services. Migrating from Render: If your Render service is a Docker container, the migration is mostly mechanical: ship the same Dockerfile, set the same env vars, and you're live. `bunx percher init` generates a `percher.toml` from your project that points at the existing Dockerfile (set `runtime = "docker"`), and `bunx percher publish` builds and deploys it. Custom domains move with a one-time DNS update. What doesn't carry over directly: Render's managed Postgres and Redis are separate services on Render but have no direct equivalent on Percher — the Percher pattern is the opt-in PocketBase sidecar (`[data] mode = "pocketbase"`) for SQLite + auth + file storage, or `DATABASE_URL` pointed at any external Postgres provider (Neon, Supabase, your own). Background workers and cron jobs on Render need to be folded into your main app for now (a long-running queue consumer thread, or an external cron-as-a-service hitting a webhook); Percher doesn't expose those as distinct service types yet. ```sh # In your project root (with your existing Dockerfile): bunx percher init # generates percher.toml (runtime=docker) bunx percher env set DATABASE_URL=... # for each env var on Render bunx percher publish # build + deploy bunx percher domains add yourdomain.com ``` FAQ: **Can I run my Render Docker service on Percher?** Yes. If your Render service uses a `Dockerfile` (the common case), Percher builds and runs the exact same image with `runtime = "docker"` in `percher.toml`. No code changes are needed — only your `DATABASE_URL` and other env vars have to be re-set with `bunx percher env set`. The build pipeline picks up your Dockerfile automatically when `bunx percher init` detects it in the project root. **Is Percher cheaper than Render?** For a single small app, the two are roughly comparable at the entry level. Where Percher wins on cost is multi-app usage: Render charges per service (each web service, each Postgres, each Redis is billed separately), while Percher's flat-rate plans cover everything on one account. For one heavy app with a beefy Postgres, Render can be cheaper because you only pay for what you use; for three or four small apps, Percher's flat plans are typically less. **Does Percher support multi-region like Render?** No. Percher runs in a single EU region (Germany). Render offers US, EU, Asia, and Australia regions. If your audience needs sub-100 ms latency outside Europe, Render (or fronting Percher with a global CDN) is the right call. For European audiences, Percher's single region is fine. **What replaces Render's managed Postgres?** Percher doesn't ship a managed Postgres of its own today. Every app can opt into a managed PocketBase sidecar (SQLite + auth + S3-compatible file storage) by setting `[data] mode = "pocketbase"` — the sidecar is provisioned automatically and reachable via the `POCKETBASE_URL` env var. For raw Postgres specifically, point `DATABASE_URL` at any external provider (Neon, Supabase, your own server) and Percher's outbound proxy handles the connection transparently. **How do I run a background worker on Percher?** Render models workers as a distinct service type; Percher doesn't, yet. The current pattern is to fold the worker into your main app — start a background task (queue consumer, scheduler, etc.) at app boot, in the same process or as a child process inside the same container. For periodic jobs, external cron-as-a-service (GitHub Actions on a schedule, EasyCron, etc.) hitting a webhook endpoint is the common workaround. ## Percher vs Fly.io Percher vs Fly.io. Fly.io is a global infrastructure platform: Firecracker microVMs you can place in 30-plus regions, anycast routing, per-region volumes, and a Machines API that treats every box like a primitive. It rewards power users who want low-level control and global distribution. Both Fly and Percher ship MCP servers today (flyctl bundles an `mcp` subcommand); the design distance is bigger than that one feature, though. Percher is the opposite end of the design space from Fly — one region in Germany, one container per app, no machine APIs to wire up, and MCP as the primary deploy surface (49 tools and a typed `recovery.nextAction` contract). Pick Fly if you need geo-distribution or raw infrastructure primitives; pick Percher if you want zero-config hosting your assistant can drive end-to-end through recovery loops instead of just one-shot deploys. Who Percher is for: Percher is for personal and small-scale apps: things you build for yourself, your family, a club or association, or a smaller business or organisation. It is not enterprise or production-grade hosting, by design, and the reasons are concrete. One region means no geographic failover, so a regional outage takes the app fully down with no automatic recovery. There is no uptime SLA, so nothing contractually guarantees it stays up or compensates you when it doesn't. And there is no SOC 2 or HIPAA attestation, so it can't clear enterprise security or compliance review. If you're running a monetised SaaS with paying customers, an app under a customer contract, or anything where downtime has financial or legal consequences, a higher-tier provider is the right call. At a glance: | Feature | Percher | Fly.io | | --- | --- | --- | | Free tier | Free plan (3 apps, sleep after 20 min idle) | No free tier (pay-as-you-go from first machine) | | Paid entry price | €3/mo (Starter) — flat, per account | Pay-as-you-go: per-machine, per-hour, per-GB | | Pricing model | Flat monthly subscription per account | Metered: CPU-seconds, RAM-hours, bandwidth, volumes | | Region | Single EU region (Germany) | 30+ regions worldwide | | Compute model | One long-running container per app | Firecracker microVMs via the Machines API | | Built-in database | Opt-in managed PocketBase per app via `[data] mode = "pocketbase"` (SQLite, auth, file storage) | Fly Postgres (separate, regional) | | Built-in auth | Yes (when PocketBase is enabled) — auth out of the box with PocketBase | No — bring your own | | MCP server | MCP-first: 49 tools covering publish, logs, env, rollback, doctor, backups, domains and GitHub connect, plus a typed `recovery.nextAction` for chaining failures into fixes | flyctl bundles `flyctl mcp` for Fly resource management (apps, machines, deploys) | | Framework support | Node, Bun, Python, static, any Dockerfile | Any Dockerfile / OCI image | | Multi-region deploy | Not supported (single region by design) | First-class — `fly scale count N --region ` per region | | Custom domains | Yes (paid plans) | Yes | | Automatic SSL | Yes — Let's Encrypt via Caddy | Yes — Let's Encrypt | | Networking primitives | Standard HTTPS in + outbound proxy out | WireGuard private networking, anycast, fly-replay, IPv6 | | Rollback | Instant per-deploy rollback | Instant per-deploy rollback (image-based) | When Percher is the better choice: - You want the assistant doing more than `publish` — full operational tools (logs, env, rollback, doctor, backups, domain add) and a typed `recovery.nextAction` that turns a failed deploy into the next fix automatically. - Your project is small and single-region, and Fly's pay-as-you-go pricing makes the monthly bill harder to predict than a flat-rate plan. - You want an opt-in managed PocketBase per app (`[data] mode = "pocketbase"`) for SQLite + auth + file storage instead of standing up Fly Postgres as a separate billed service. - Your project must stay in the EU for data-residency reasons. Percher is single-region in Germany. - You want a zero-config deploy that 'just works' for a Node, Bun, Python, or static app without writing a `fly.toml`. When Fly.io is the better choice: - You need real multi-region distribution — the same app running in São Paulo, Tokyo, and Frankfurt with local latency for each. That's Fly's whole pitch and Percher cannot match it. - You want low-level infrastructure primitives: WireGuard private networking, IPv6 anycast, per-region volumes, the Machines API for dynamic provisioning. Percher abstracts those away. - Your workload is bursty and benefits from scale-to-zero with fast Firecracker cold starts. Percher containers are long-running by design. - You need fine-grained control over instance types, regions, and per-region replica counts. Fly exposes those; Percher hides them. - You're already invested in the Fly ecosystem — Fly Postgres, Tigris object storage, Upstash add-ons — and don't want to migrate them. Migrating from Fly.io: Fly apps are Docker-first, so the migration is mechanical in the common case: take your existing `Dockerfile`, run `bunx percher init` in the project root (it'll detect the Dockerfile and write `runtime = "docker"` in `percher.toml`), and `bunx percher publish` builds and deploys the same image Fly was building. Env vars don't move automatically — copy them from `fly secrets list` and re-set with `bunx percher env set`. Domains move with a one-time DNS update once the app is live. What doesn't translate: anything that depends on Fly being globally distributed. If your app uses `fly-replay`, region-aware routing, or per-region volumes, you'll need to decide whether single-region in Germany is acceptable (often: yes, for European audiences) or whether you need to keep Fly. WireGuard-based private networking between Fly services becomes plain HTTPS-over-Percher-proxy on Percher. Fly Postgres has no direct equivalent — point `DATABASE_URL` at any external Postgres (Neon, Supabase, your own) and Percher's outbound proxy handles the connection. ```sh # In your project root (with your existing Dockerfile): fly secrets list # copy each secret bunx percher init # generates percher.toml (runtime=docker) bunx percher env set DATABASE_URL=... # for each Fly secret bunx percher publish # build + deploy bunx percher domains add yourdomain.com ``` FAQ: **Can Percher run a multi-region app like Fly does?** No. Percher is single-region by design — every app runs in a single EU region (Germany). That's the trade-off for simplicity and flat-rate pricing. If you need the same app running in São Paulo, Tokyo, and Frankfurt with local latency for each, Fly is built for that and Percher isn't. **Is Percher cheaper than Fly?** For a small, single-region app, almost always — Fly's pay-as-you-go bill (per-CPU-second, per-RAM-hour, per-GB bandwidth) tends to surprise people on the upside, while Percher's flat plans (€0 / €3 / €12 / €29 per month) are predictable. For an app that genuinely needs Fly's multi-region distribution or Machines API features, the comparison breaks down — Percher cannot run that workload at all. **What about Fly Postgres?** Fly Postgres is a separate, regional managed Postgres on Fly's infrastructure. Percher has no equivalent — there is no managed Postgres on Percher today. The Percher pattern for new apps is the opt-in PocketBase sidecar (`[data] mode = "pocketbase"`) for SQLite + auth + S3-compatible file storage, and `DATABASE_URL` pointed at any external Postgres provider (Neon, Supabase, your own) when you need real Postgres. Percher's outbound HTTPS proxy handles the connection transparently. **Can I run my Fly Dockerfile on Percher?** Yes. If your `fly.toml` points at a Dockerfile, that's the path: `bunx percher init` detects it, writes `runtime = "docker"` in `percher.toml`, and `bunx percher publish` builds and runs the same image. Anything Fly-specific in the Dockerfile (rare) needs adjustment — most don't have anything Fly-specific. **How does Percher's deploy model differ from Fly's Machines API?** Fly's Machines API treats every VM as a primitive you can start, stop, and place yourself — useful for workflows like 'spin up a sandbox per request' or 'place a worker near the user's region'. Percher's model is simpler and more constrained: one app, one (or a few) long-running containers, no machine API. If your app is built around dynamic VM lifecycle, Percher is the wrong tool. If it's a normal web app, the Machines API is more power than you need. ## Percher vs Railway Percher vs Railway. Railway is a polished modern PaaS in the Heroku tradition: click a template, link a GitHub repo, attach a managed Postgres or Redis, and you're live. Both Railway and Percher ship MCP servers today, so 'AI assistant can deploy' is true on both sides. The real differences are depth and shape. Railway is an excellent fit for traditional 12-factor app workflows with a small team and a mature web UI. Percher is built around MCP as the primary deploy surface — 49 tools covering the full operational loop and a typed `recovery.nextAction` contract so a failed deploy chains into the next fix automatically. If you prefer a polished web UI with a deep template marketplace, Railway is more refined; if you want the assistant to run the whole operational loop and a flat monthly bill, Percher fits that workflow. Who Percher is for: Percher is for personal and small-scale apps: things you build for yourself, your family, a club or association, or a smaller business or organisation. It is not enterprise or production-grade hosting, by design, and the reasons are concrete. One region means no geographic failover, so a regional outage takes the app fully down with no automatic recovery. There is no uptime SLA, so nothing contractually guarantees it stays up or compensates you when it doesn't. And there is no SOC 2 or HIPAA attestation, so it can't clear enterprise security or compliance review. If you're running a monetised SaaS with paying customers, an app under a customer contract, or anything where downtime has financial or legal consequences, a higher-tier provider is the right call. At a glance: | Feature | Percher | Railway | | --- | --- | --- | | Free tier | Free plan (3 apps, sleep after 20 min idle) | Trial credits on signup, then paid | | Paid entry price | €3/mo (Starter) — flat, per account | Hobby: $5/mo minimum + metered usage on top — as of 2026-05 | | Pricing model | Flat monthly subscription per account | Base plan + metered (vCPU, memory, egress, volumes) | | Region | Single EU region (Germany) | Multi-region (US East/West, EU West, SE Asia) | | Compute model | Long-running containers per app | Long-running services on shared infrastructure | | Built-in database | Opt-in managed PocketBase per app via `[data] mode = "pocketbase"` (SQLite, auth, file storage) | Managed Postgres, MySQL, Redis, MongoDB (one-click) | | Built-in auth | Yes (when PocketBase is enabled) — auth out of the box with PocketBase | No — bring your own | | MCP server | MCP-first: 49 tools covering publish, logs, env, rollback, doctor, backups, domains and GitHub connect, plus a typed `recovery.nextAction` for chaining failures into fixes | Has an MCP server for project / service / env management (Railway MCP) | | Framework support | Node, Bun, Python, static, any Dockerfile | Nixpacks auto-detect, any Dockerfile | | Template marketplace | 29+ starter templates via `bunx percher create` | Extensive template marketplace with one-click deploy | | Background workers / cron | Not first-class (use a single long-running app) | Cron jobs first-class; workers as separate services | | Custom domains | Yes (paid plans) | Yes | | Automatic SSL | Yes — Let's Encrypt via Caddy | Yes — Let's Encrypt | | Rollback | Instant per-deploy rollback | Instant per-deploy rollback | When Percher is the better choice: - You want the assistant doing more than `publish` — full operational tools (logs, env, rollback, doctor, backups, domain add) and a typed `recovery.nextAction` that chains a failed deploy into the next fix without a dashboard switch. - You want predictable flat-rate pricing — €0 / €3 / €12 / €29 per month — not a base plan plus metered vCPU / RAM / egress charges. - You want an opt-in managed PocketBase per app (`[data] mode = "pocketbase"`) for SQLite + auth + file storage instead of standing up a managed Postgres plus a separate auth provider. - Your project must stay in the EU. Percher runs in Germany only. - You're a solo builder and Railway's metered model can produce surprise bills on bursty workloads. When Railway is the better choice: - You prefer a polished web UI as your primary deploy surface — Railway has one of the best in the PaaS space and Percher's dashboard is intentionally minimal. - You need managed Postgres, MySQL, Redis, or MongoDB as one-click services. Railway's template marketplace makes this trivial; Percher only offers an opt-in PocketBase sidecar plus external `DATABASE_URL` for anything else. - You want a deep template marketplace — Railway has hundreds of community templates ready to fork. - You need background workers or cron jobs as first-class service types. Railway supports cron jobs natively; Percher doesn't yet. - Your audience needs sub-100 ms latency in the US or Asia — Railway has US East/West and Singapore regions; Percher is Germany-only. Migrating from Railway: Most Railway services migrate to Percher with a one-line change. If your service is a Dockerfile-driven app, `bunx percher init` detects it and writes `runtime = "docker"` in `percher.toml`; if it's a Nixpacks-built Node/Bun/Python app, Percher uses its own builders for Node and Bun (and falls back to Nixpacks for Python) so the build feels familiar. Copy env vars from Railway's variables UI and re-set with `bunx percher env set`. Domains move with a one-time DNS update. What doesn't carry over directly: Railway's managed databases (Postgres, MySQL, Redis, MongoDB) are first-class one-click services there but have no equivalent on Percher today. The Percher pattern is the opt-in PocketBase sidecar (`[data] mode = "pocketbase"`) for SQLite + auth + file storage, plus external providers for anything else — point `DATABASE_URL` / `REDIS_URL` at Neon, Supabase, Upstash, your own server, etc. Railway cron jobs need to be replaced with an external scheduler (GitHub Actions on cron, EasyCron) hitting a webhook endpoint until Percher adds first-class cron. ```sh # In your project root: bunx percher init # detects framework, generates percher.toml bunx percher env set DATABASE_URL=... # for each Railway variable bunx percher publish # build + deploy bunx percher domains add yourdomain.com ``` FAQ: **Can I deploy a Nixpacks-built Railway app to Percher?** Yes. For Node and Bun apps, Percher uses its own multi-stage Dockerfile generator (faster cold builds, ~225 MB images). For Python and other runtimes Percher falls back to Nixpacks too, using the same upstream binary Railway does — so the build environment is familiar. Custom `nixpacks.toml` files apply: Percher's nixpacks fallback reads them the same way. **Is Percher cheaper than Railway?** For a few small apps, almost always — Percher's flat plans (€0 / €3 / €12 / €29 per month) cover the whole account, while Railway charges a base plan plus metered usage on top. For a single app with very high traffic and managed databases, Railway's per-resource model can be more cost-effective. Run the math against your current Railway bill; the metered breakdown is in Railway's billing dashboard. **What replaces Railway's managed Postgres / MySQL / Redis?** Percher doesn't ship a managed Postgres / MySQL / Redis today. Every app can opt into the managed PocketBase sidecar (SQLite, authentication, S3-compatible file storage) by setting `[data] mode = "pocketbase"` in `percher.toml` — Percher provisions it on first deploy and injects `POCKETBASE_URL` automatically. For raw Postgres, MySQL, or Redis, point `DATABASE_URL` / `REDIS_URL` at any external provider (Neon, PlanetScale, Supabase, Upstash); Percher's outbound HTTPS proxy handles the connections transparently. **Can Percher do template-based deploys like Railway?** Percher has its own template gallery (`bunx percher create app --template `) covering 29+ starter templates — Next.js, SvelteKit, Astro, Vite (React/Vue), FastAPI, Flask, Django, Eleventy, Hugo, and more. It's smaller than Railway's marketplace, but the templates are all production-ready and version-pinned. The `percher init` command also adapts to whatever you already have in the project root, so you rarely need a template after the first project. **How do I run a cron job on Percher?** Railway supports cron jobs as a first-class service type; Percher doesn't, yet. The current pattern is either an external scheduler (GitHub Actions on a schedule, EasyCron, etc.) calling a `/api/cron/` webhook in your app, or an in-process scheduler (a setInterval at startup) for jobs that fit the same process. First-class cron is on the roadmap but not yet shipped. ## Percher vs Lovable Percher vs Lovable. Lovable and Percher are not really competitors — they sit at different layers of the stack. Lovable is an AI app builder: you describe what you want in a chat, and it generates a React + Vite + Supabase project plus a preview URL you can share — and on paid plans, custom domains and real deployment. So this isn't a hosting comparison; both can host. The pattern this page is about is the bridge: build in Lovable, host on Percher. People do this when they want the Lovable build experience but want hosting on infrastructure separate from the AI builder — your own domain, runtime logs, per-deploy rollback, flat per-account pricing that doesn't depend on builder token usage, and EU data residency. Percher is the second host you keep code on once Lovable has done the building part — best fit for personal projects, not for monetised SaaS or anything that needs a formal uptime SLA. Who Percher is for: Percher is for personal and small-scale apps: things you build for yourself, your family, a club or association, or a smaller business or organisation. It is not enterprise or production-grade hosting, by design, and the reasons are concrete. One region means no geographic failover, so a regional outage takes the app fully down with no automatic recovery. There is no uptime SLA, so nothing contractually guarantees it stays up or compensates you when it doesn't. And there is no SOC 2 or HIPAA attestation, so it can't clear enterprise security or compliance review. If you're running a monetised SaaS with paying customers, an app under a customer contract, or anything where downtime has financial or legal consequences, a higher-tier provider is the right call. At a glance: | Feature | Percher | Lovable | | --- | --- | --- | | Primary role | Hosting platform for personal apps | AI-driven app builder; ships native preview + paid live hosting | | How you create the app | Write code (or have your AI assistant do it) | Describe in a chat; Lovable generates the code | | AI assistant integration | MCP server — works with any MCP-capable assistant | Built-in chat-based AI (their own surface) | | Free tier | Free plan (3 apps, sleep after 20 min idle) | Daily message limit on Free tier | | Paid entry price | €3/mo (Starter) — flat, per account | Paid plans for higher message / project limits | | Hosting jurisdiction | EU only (Germany) | US-based platform | | Backend default | Opt-in managed PocketBase (SQLite + auth + file storage) via `[data] mode = "pocketbase"` | Supabase (Postgres, auth, storage) | | Custom domains | Yes (paid plans) | Yes (paid plans) | | Rollback / version history | Instant per-deploy rollback via CLI or MCP tool call | In-chat undo / restore previous version + GitHub history | | Source code ownership | You own and host the code anywhere | GitHub sync exports a standard npm project — no lock-in | | Operational visibility for live traffic | Runtime logs, build logs, deploy history, metrics — accessible via CLI / MCP / dashboard | Tuned for the build-iterate-preview loop more than for diagnosing live-traffic issues | When Percher is the better choice: - You want hosting separated from the AI builder — different vendors, different bills, different reliability domains. Lovable's hosting works; this is about keeping it untangled. - Your daily AI assistant is Claude Code, Cursor, or Windsurf rather than Lovable's chat, and you want operational tools (publish, logs, env, rollback, doctor) accessible to that assistant via MCP. - You want flat per-account hosting cost decoupled from AI builder token usage. On Percher the hosting bill is €0 / €3 / €12 / €29 per month regardless of what tools you use to write the code. - Your hosting must stay in the EU for data-residency reasons. Percher runs in Germany only; Lovable's hosting is US-based. - You want full operational visibility — runtime logs, build logs, deploy history, metrics — tuned for diagnosing live-traffic issues, not just preview-iteration. When Lovable is the better choice: - You're still in the prototype phase and want the AI to write the code, not just host it. Lovable is excellent for that part; Percher doesn't build apps for you. - You haven't written any code yet and a chat-based AI builder is the fastest path from idea to running preview. - You want one vendor handling both the build experience and the live hosting, with the in-chat workflow staying intact across milestones — Lovable's bundled hosting is well-tuned for that. - You're invested in Lovable's chat-based workflow for non-developers — designers, founders, PMs spinning up internal tools — and the production-host split would add friction. - Your team's review loop is happening inside Lovable (in-chat preview, branch-style versions, comment threads on prompts) and moving to Percher would split that workflow. Migrating from Lovable: The migration path is straightforward because Lovable lets you sync the project to GitHub. Once your Lovable project is in a repo, clone it locally, run `bunx percher init` to detect the Vite framework (Lovable scaffolds Vite + React by default), and `bunx percher publish` builds and deploys it. The Vite app ships as `runtime = "docker"` with a multi-stage build (Bun stage compiles, slim Caddy stage serves the static bundle) — `init` scaffolds the Dockerfile and Caddyfile automatically. Your Supabase backend keeps working unchanged. Copy the Supabase URL and anon key from Lovable's env vars and re-set with `bunx percher env set VITE_SUPABASE_URL=...` and `bunx percher env set VITE_SUPABASE_ANON_KEY=...` — Percher auto-forwards any `VITE_*` env var to the build, so the values reach your client bundle without further configuration. Custom domain moves with a one-time DNS update. The app stays connected to the same Supabase project; only the host changes. ```sh # 1. In Lovable: sync your project to GitHub # 2. Clone the repo locally: git clone https://github.com/you/your-lovable-project cd your-lovable-project bunx percher init # detects Vite, scaffolds Dockerfile + Caddyfile bunx percher env set VITE_SUPABASE_URL=https://xxx.supabase.co bunx percher env set VITE_SUPABASE_ANON_KEY=eyJ... bunx percher publish # build + deploy bunx percher domains add yourdomain.com ``` FAQ: **Do I have to stop using Lovable to ship on Percher?** No. The pattern is build in Lovable, host on Percher — keep using Lovable's chat to iterate on the app, sync to GitHub when you're happy with a milestone, and re-deploy to Percher with `bunx percher publish`. Lovable handles the build-by-chat workflow; Percher serves the live URL. The two layers are independent. **Does my Supabase setup still work on Percher?** Yes, with no changes. Supabase is an external service hit over HTTPS; Percher's outbound proxy handles the connection. Copy `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` from Lovable's env vars and re-set them on Percher with `bunx percher env set`. The `VITE_*` prefix means they're auto-forwarded to the build container and baked into your client bundle. **Can I use Claude Code or Cursor with Percher instead of Lovable's AI?** Yes — that's Percher's positioning. Install Percher's MCP server (`bunx percher mcp` prints the config), point Claude Code, Cursor, or Windsurf at it, and the assistant gets `publish`, `logs`, `env`, `rollback`, and 50-plus other tools as native MCP calls. Your AI assistant and your hosting platform stop being separate apps you context-switch between. **Is Percher cheaper than Lovable?** They bill for different things. Lovable charges for the AI builder — message limits and project counts on tiers, separate from any hosting. Percher charges flat per account for hosting only — €0 / €3 / €12 / €29 per month. If you migrate the app off Lovable and use Claude / Cursor / Windsurf as your AI (with their own subscriptions), Percher replaces the hosting half. The total can be cheaper or more expensive depending on which AI tools you're already paying for. **What if my Lovable app uses Supabase auth — will users still log in?** Yes. Supabase auth is server-side at api.supabase.co; the only thing changing is where the static React bundle is served from. As long as your Supabase project still has the new Percher URL whitelisted under Authentication → URL Configuration (so OAuth redirects and email confirmations come back to the right place), every existing user account keeps working. ## Percher vs Bolt.new Percher vs Bolt.new. Bolt.new is StackBlitz's in-browser AI dev environment — describe an app in chat, iterate on it with a full terminal and file tree running entirely in the tab via WebContainer. Bolt ships its own production hosting (with custom domains and built-in databases) on top of that, so this isn't a hosting-or-no-hosting comparison. The pattern this page is about is the bridge: build in Bolt, host on Percher. People do that when they want hosting separated from the builder — your own infrastructure, flat per-account pricing decoupled from AI token usage, and EU data residency — while keeping Bolt as the chat-driven dev environment for further iteration. Who Percher is for: Percher is for personal and small-scale apps: things you build for yourself, your family, a club or association, or a smaller business or organisation. It is not enterprise or production-grade hosting, by design, and the reasons are concrete. One region means no geographic failover, so a regional outage takes the app fully down with no automatic recovery. There is no uptime SLA, so nothing contractually guarantees it stays up or compensates you when it doesn't. And there is no SOC 2 or HIPAA attestation, so it can't clear enterprise security or compliance review. If you're running a monetised SaaS with paying customers, an app under a customer contract, or anything where downtime has financial or legal consequences, a higher-tier provider is the right call. At a glance: | Feature | Percher | Bolt.new | | --- | --- | --- | | Primary role | Hosting platform for personal apps | In-browser AI dev environment + native production hosting | | Where the app runs while you build | On your Percher container after each `publish` | Inside WebContainer (Node in the browser tab) | | AI assistant integration | MCP server — Claude Code / Cursor / Windsurf as your daily driver | Built-in chat-based AI (their own surface) | | Free tier | Free plan (3 apps, sleep after 20 min idle) | Daily token limit on Free tier | | Paid entry price | €3/mo (Starter) — flat, per account | Paid tiers raise the daily token allowance | | Pricing model | Flat monthly hosting subscription | Token-metered AI usage (LLM cost passed through) | | Hosting jurisdiction | EU only (Germany) | US-based platform (StackBlitz) | | Where the live URL lives | Percher itself — `name.percher.run` and custom domains | Bolt's native hosting, or built-in Netlify deploy integration | | Backend defaults | Opt-in managed PocketBase via `[data] mode = "pocketbase"` (SQLite + auth + file storage) | Often Supabase or external APIs; varies by prompt | | Source code ownership | You own and host the code anywhere | Download as a normal npm project at any time | | Custom domains | Yes (paid plans) | Yes on paid plans (Bolt-native or via the Netlify integration) | | Operational visibility for live traffic | Runtime logs, build logs, deploy history, metrics — accessible via CLI / MCP / dashboard | Tuned for the in-tab build loop more than for live-traffic diagnosis | When Percher is the better choice: - You've prototyped a project in Bolt and want a separate hosting platform — your own domain, runtime logs, per-deploy rollback, predictable monthly cost. - You want hosting separated from your AI tool spend. Bolt bundles AI tokens with the live preview; Percher bills hosting only and is independent of which AI tool you use. - Your daily AI assistant is Claude Code, Cursor, or Windsurf and you want every operation as a native MCP tool call — `publish`, `logs`, `env`, `rollback`, `doctor` — without leaving the assistant. - Your hosting must stay in the EU. Percher runs in Germany only; Bolt and StackBlitz are US-based. - You want a Linux container, an opt-in managed PocketBase sidecar, env vars, and a deploy history rather than the in-tab WebContainer model. When Bolt.new is the better choice: - You're still in the prototyping phase and want a chat-driven dev environment with a full terminal and file tree in the browser. WebContainer is genuinely impressive technology and Percher doesn't try to compete with it. - You don't have a local development setup and don't want one — Bolt runs Node entirely in your browser tab. - Bolt's native hosting or its Netlify deploy integration covers your needs and the extra hop to a separate host isn't worth the operational split. - You're early enough in the project that the AI builder is doing most of the work and you'd rather pay one bundled bill than separate tools. - You're already inside the StackBlitz ecosystem and the in-tab dev loop matches how you work. Migrating from Bolt.new: Bolt projects download as standard npm packages — there's no proprietary format you have to convert. Click the download button (or push to GitHub from inside Bolt), clone the result locally, and `bunx percher init` detects whatever framework Bolt scaffolded (usually Vite + React, sometimes Next.js or SvelteKit) and writes a working `percher.toml`. `bunx percher publish` builds and deploys it. For Vite apps the project ships as `runtime = "docker"` with a multi-stage build (Bun stage compiles, slim Caddy stage serves) — `init` scaffolds both the Dockerfile and Caddyfile automatically. External services keep working unchanged. If Bolt generated an app that talks to Supabase or any external API, copy those env vars (`bunx percher env set VITE_SUPABASE_URL=...`, etc.) — Percher auto-forwards anything matching `VITE_*` / `NEXT_PUBLIC_*` / `PUBLIC_*` to the build container so the values land in your client bundle. Custom domain is one DNS update after the first deploy. ```sh # 1. In Bolt: download the project, or push to GitHub # 2. Clone locally: git clone https://github.com/you/your-bolt-project cd your-bolt-project bunx percher init # detects framework, scaffolds Dockerfile if needed bunx percher env set VITE_SUPABASE_URL=... # for each Bolt env var bunx percher publish # build + deploy bunx percher domains add yourdomain.com ``` FAQ: **Do I have to stop using Bolt to ship on Percher?** No. The pattern is build in Bolt, host on Percher. Keep using Bolt's chat to iterate on the app, sync to GitHub when you have a milestone, and re-deploy with `bunx percher publish`. Bolt's in-browser dev environment and Percher's hosting are independent — one's job is rapid iteration with an AI in the loop, the other's job is keeping the live URL up. **Can I use Claude Code or Cursor with Percher instead of Bolt's AI?** Yes — that's the core difference. Percher's MCP server (`bunx percher mcp` prints the config) plugs into Claude Code, Cursor, Windsurf, or any MCP-capable assistant, giving the assistant `publish`, `logs`, `env`, `rollback`, and 50-plus other tool calls. Your AI assistant and your hosting platform stop being separate apps you switch between. **What if my Bolt app uses Supabase?** It keeps working unchanged. Supabase is reached over HTTPS; Percher's outbound proxy handles the connection. Copy `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` (or whichever prefix your framework uses — `NEXT_PUBLIC_*` for Next, `PUBLIC_*` for SvelteKit/Astro) and re-set with `bunx percher env set`. Those prefixes auto-forward to the build container so the values are baked into your client bundle. **Is Percher cheaper than Bolt?** They bill for different things. Bolt charges token-based pricing for the AI builder; Percher charges flat per account (€0 / €3 / €12 / €29 per month) for hosting only. If you move to your own AI subscription (Claude / Cursor / Windsurf) for the build side and Percher for the host side, the total can be cheaper or more expensive depending on token usage. The two costs are independent on Percher; on Bolt they're bundled. **Does Bolt's WebContainer have a Percher equivalent?** No, and Percher isn't trying to build one. WebContainer runs Node entirely in the browser tab — useful for in-tab iteration but a different shape from hosting a live URL. Percher's compute is real Linux containers in an EU region with a fixed resource budget per plan. Different tools for different stages of the project's life.