A Vercel alternative for static output
If the thing you deploy is a folder of files, you are paying for a framework runtime you are not running.
Vercel is a framework platform. Its centre of gravity is Next.js and the rendering model around it — server components, edge middleware, ISR, functions — and if you are running that, Vercel is where it runs best. Nothing here argues otherwise.
But a large share of what gets deployed to Vercel is a static export: an Astro, Vite, Hugo, Eleventy or SvelteKit build that produced plain HTML, CSS and JS. For that, the runtime is not doing anything — you are on a usage-priced platform for an artifact that never executes. One9x Pages hosts exactly that artifact, at a flat price, with the parts you actually use kept: atomic releases, a preview URL per release, and instant rollback.
Where the two actually differ
Structural differences only — what each product fundamentally is. No plan names and no prices for Vercel, because those change without telling us and a stale number here would mislead exactly the person who came to check one.
What it is for
One9x Pages
Static output, whatever produced it. No framework is privileged.
Vercel
Framework runtimes, with Next.js as the first-class case.
How the bill is shaped
One9x Pages
One flat figure per month per plan. Nothing meters.
Vercel
Plan plus usage — the shape that makes a traffic spike a billing event.
Team members
One9x Pages
Not a billing dimension. Plans are limits on sites, storage and domains.
Vercel
Seats are part of how team plans are priced.
Uploads
One9x Pages
Content-addressed: your machine hashes the folder, only unseen files go up.
Vercel
Builds and deploys through the platform pipeline.
Vendor shape
One9x Pages
Plain files. Leaving means pointing DNS elsewhere — nothing to port.
Vercel
Framework features that only exist on the platform if you adopt them.
Deploying from an agent
One9x Pages
The CLI is an MCP server. An agent deploys a folder in one tool call.
Vercel
Supported, through the platform’s own integrations.
Pull request previews
One9x Pages
Our GitHub Action stages a release per PR and comments the preview URL, editing that one comment on every push.
Vercel
Created automatically from the Git connection.
When to stay on Vercel
Three cases where moving would cost you something we cannot give back. If one of them is yours, this is the wrong product and you should not have to read to the bottom of a sales page to find that out.
- You run Next.js with server rendering, ISR, middleware or route handlers. Those are the product. A static host cannot host them and we will not pretend otherwise.
- You use Vercel’s functions, KV, blob or AI SDK infrastructure. Pages has none of that; it serves files.
- Your repository is on GitLab or Bitbucket. Vercel connects to those natively; our push-to-deploy is a GitHub Action, and elsewhere it is a three-line shell step you add yourself.
Moving a site from Vercel
What your configuration maps to, what has no equivalent at all, and the order to do it in. The middle one is the part that decides whether this is an afternoon.
What maps to what
| On Vercel | Here |
|---|---|
vercel.json → outputDirectory | The directory you hand to the deploy. |
| Build command and framework preset | Runs in your own CI — the GitHub Action workflow. |
rewrites sending everything to /index.html | --spa. |
A 404.html or framework not-found page | --error 404:/404.html. |
| Preview deployments per pull request | The Action stages a release per PR and comments the URL, editing one comment. |
| Environment variables for the build | Repository secrets in your CI. |
| Instant rollback to a previous deployment | one9x pages deploy --to v6, or the dashboard. A pointer flip. |
| Ignoring files at deploy time | --exclude, repeatable. |
What has no equivalent
Handle these before you move DNS, not after. Pages serves files: it has an SPA fallback, custom error pages and an exclude list, and it has no redirect table and no custom response headers.
- Anything that executes. Route handlers, middleware, ISR, server components,
api/functions. Ifoutput: ’export’does not produce a working site, that is the signal to stay rather than a problem to work around. -
rewrites,redirectsandheadersinvercel.json, apart from the SPA fallback. No redirect table and no custom headers exist here. -
cleanUrlsandtrailingSlash. We serve what your build produced, at the paths it produced. Set these in your framework so the output is already the shape you want.
The order to do it in
-
STEP 01
Prove it builds to static output first
Before anything else. For most frameworks this is the adapter or flag you already have; for Next.js it isoutput: ’export’. If this build fails, stop reading — your app needs a runtime and the honest answer is to stay on Vercel.next.js// next.config.js module.exports = { output: 'export' } -
STEP 02
Account for vercel.json
List what it actually does.rewrites,redirects,headers,cleanUrls,trailingSlash— each one either becomes a build setting, becomes a real file in your output, or goes away. Only the catch-all rewrite has a direct equivalent, and it is--spa. -
STEP 03
Create the site and a CI token
A site has to exist before anything can deploy to it — the action will not create one, so a typo fails instead of quietly publishing to a new address. Do both from the dashboard if you prefer.once$ one9x pages create mysite ✓ created mysite → https://mysite.one9x.app/ $ one9x tokens create "github actions" one9x_tok_7Kd… (shown once) -
STEP 04
Deploy the output directory and walk the routes
Staging costs nothing and the preview is byte-identical to what would go live. Walk the routes here: a framework that was quietly relying on the platform shows up now rather than after the DNS change.first deploy$ one9x pages release ./out --site mysite ✓ v1 staged → https://v1--mysite.one9x.app/ -
STEP 05
Swap the deploy step in CI
If you deploy through Vercel’s Git integration, you are writing your first workflow — GitHub Actions has the whole file. If you already run a Vercel action, it comes out and this goes in, and you get the PR previews back with it.before- uses: amondnet/vercel-action@v25 with: vercel-token: ${{ secrets.VERCEL_TOKEN }} vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} vercel-args: '--prod'after- uses: one9x/pages-deploy@v1 with: site: mysite dir: out token: ${{ secrets.ONE9X_TOKEN }} deploy: ${{ github.ref == 'refs/heads/main' }} comment: true -
STEP 06
Cut the domain over
Lower the TTL a day ahead, link the domain here, publish the records we print, and let the certificate issue. Your Vercel deployment keeps serving until DNS actually moves, so there is no window where neither answers. -
STEP 07
Decommission
Remove the project from Vercel once traffic has moved, and deletevercel.jsonfrom the repo so it is not mistaken for live config later.
Your live site on Vercel keeps serving throughout — nothing here touches it until you move DNS, and the free plan is enough to do the whole rehearsal first.
Try it with one site
The free plan takes three sites, no card, and does not expire. Deploy the folder you already have and see what it looks like before anything moves.