Web hosting (Sites)
Host static sites and single-page apps on <site>.sovaria.app and your own domains: deploys that upload only changed files, instant rollback, preview channels, redirects, rewrites to functions and SPA fallback.
A site serves a build folder (Vite, React, Vue, Svelte, Astro, a Next.js static export, docs, a landing page) at https://<site>.sovaria.app — a domain of its own, separate from the console and the API, so a page can never read or set their cookies — and at any custom domain you connect. Every deploy is immutable; a release points the site at one deploy in a single step, so visitors see the old site or the new one, never a mix; rollback is the same step backwards.
#Deploy a site
Create the site and its config
sov hosting init --site my-app --public dist --spa # writes the hosting section of sovaria.jsonBuild and deploy
Only files the project doesn't already have are uploaded; then the release switches the site.
npm run build && sov hosting deploy -m "new pricing page" # ✓ Deployed 214 files (3 uploaded) → https://my-app.sovaria.appRoll back if needed
sov hosting releases sov hosting rollback # the previous release, at once (or --to <deploy id>)
In the console (Hosting) you can also create sites, deploy a folder from the browser, roll back, manage preview channels, domains and deploy tokens. From code: sovaria.hosting.deployFiles(site, files) (JavaScript) or HostingClient(sov).deploy_directory(site, "dist") (Python). Sovariq can create a site and publish a page you write together.
#sovaria.json
{
"hosting": {
"site": "my-app",
"public": "dist",
"spa": true,
"cleanUrls": true,
"trailingSlash": false,
"redirects": [{ "source": "/blog/:slug", "destination": "https://blog.example.com/:slug", "type": 301 }],
"rewrites": [
{ "source": "/api/**", "function": "api" },
{ "source": "/app/**", "destination": "/app.html" }
],
"headers": [{ "source": "**/*.@(js|css)", "headers": { "Cache-Control": "public, max-age=600" } }],
"errorPage": "/404.html",
"ignore": ["**/.*", "**/node_modules/**"]
}
}| Setting | What it does |
|---|---|
spa | Requests for pages that don't exist serve /index.html (client-side routing). Missing assets (/x.png) still get 404. |
cleanUrls | /about serves about.html; /about.html redirects to /about. |
trailingSlash | true: /docs → /docs/; false: /docs/ → /docs; omitted: both work. |
redirects | source → destination with type 301/302/303/307/308. The query string is kept. |
rewrites | Serve another file, or call a function (as an HTTP function request from the visitor; it may return HTML here). |
headers | Extra response headers for matching paths (CSP, CORS, caching). Set-Cookie, Content-Type and framing headers are set by Sovaria. |
errorPage | The page sent with 404 (default /404.html when it exists). |
Patterns: ** any depth, * one segment, ? one character, {a,b} and @(a|b) alternatives, :name one segment and :name* the rest, both usable in the destination. A request is answered by the first that applies: redirects → the exact file (with cleanUrls / trailingSlash) → rewrites → the SPA fallback → the 404 page.
#Caching, compression and paths
- Content types come from the file extension (
text/html; charset=utf-8,text/javascript,font/woff2,application/wasm…). - Fingerprinted assets (
app-3f9a2b1c.js, the default for Vite and most bundlers) are cached for a year withimmutable; pages are revalidated on every visit with anETag(unchanged →304), so a release shows at once; other files for an hour. - Pre-compressed files next to an asset (
app.js.br,app.js.gz) are sent to browsers that accept them, withVary: Accept-Encoding. - Paths are strict:
.., backslashes and control characters are refused at deploy and at serve, and there are no directory listings — a path is a file in the deploy or it isn't.
#Preview channels
A channel serves its own deploy at https://<site>--<channel>.sovaria.app and expires on its own. Use one per pull request or for a stakeholder review.
sov hosting channels deploy pr-12 --expires 7d
sov hosting channels list
sov hosting channels delete pr-12With a GitHub repository linked (console › Functions › GitHub, Site folder), every push to the branch deploys the folder live, and each pull request gets a pr-<number> channel that is deleted when it closes — for prebuilt or plain static folders. To build first, use the CI flow below.
#Deploy from CI
A deploy token deploys one site and nothing else; it needs no person's session. Create it in the console (Hosting › Deploy tokens) or with sov hosting tokens create --name "GitHub Actions", and store it as the secret SOVARIA_HOSTING_TOKEN.
on: { push: { branches: [main] }, pull_request: {} }
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- run: pip install sovaria-cli
- run: sov hosting deploy --site my-app ${{ github.event_name == 'pull_request' && format('--channel pr-{0} --expires 7d', github.event.number) || '' }}
env:
SOVARIA_HOSTING_TOKEN: ${{ secrets.SOVARIA_HOSTING_TOKEN }}#Custom domains
Add the domain
sov hosting domains add www.example.com --site my-appAdd the two DNS records it shows
A TXT record proves you own the domain; a CNAME sends its traffic to Sovaria.
Verify
Console › Hosting › Domains › Check DNS, or
sov hosting domains verify <id>. TLS is issued automatically once the domain is verified and points here; ownership is re-checked regularly.
#Limits and billing
| Free | Pro | Ultra | Team | Enterprise | |
|---|---|---|---|---|---|
| Sites per project (web hosting) | 1 | 10 | 25 | 50 | 200 |
| Site files stored | 1 GB | 10 GB | 50 GB | 200 GB | 1 TB |
| Monthly site bandwidth | 2,147,483,648 | 107,374,182,400 | 536,870,912,000 | 2,199,023,255,552 | 10,995,116,277,760 |
| Custom domains for sites | 1 | 10 | 25 | 100 | 500 |
| Preview channels per site | 1 | 10 | 25 | 50 | 100 |
| Longest preview channel lifetime (days) | 7 days | 30 days | 30 days | 90 days | 90 days |
| Largest file in a site deploy | 10 MB | 50 MB | 100 MB | 100 MB | 100 MB |
| Largest site deploy | 250 MB | 1 GB | 2 GB | 5 GB | 10 GB |
| Files per site deploy | 5,000 | 20,000 | 50,000 | 100,000 | 100,000 |
| Releases kept per site for rollback | 10 | 50 | 100 | 200 | 500 |
- Stored files count each distinct file once across your sites and the releases kept for rollback; older deploys are pruned past
host.releases_kept. - Bandwidth on Free is a hard monthly cap: past it, sites answer 429 until the next month. Paid plans keep serving; site downloads count with the plan's bandwidth and are billed past it.
- Sovaria may take down a site that hosts phishing, malware or other abuse; it then answers "Site unavailable" and you are told why.
#Coming from Firebase or Supabase?
| Platform | What this is called there |
|---|---|
| Firebase | Firebase Hosting |
| Supabase | Vercel / Netlify static hosting |
| Sovaria | Web hosting (Sites) |
Moving an existing app? Migrate from Supabase or Firebase imports users (with their passwords), data, files and rules.