Migrate from Vercel to Zenifra
This guide shows, field by field, where to find each setting of a project in the Vercel dashboard and where to enter the same value in the Zenifra console. It covers Next.js apps, static sites and SPAs (Vite, React, Vue, Astro), and APIs built with Vercel Functions. For the general plan, with data copy and DNS switch, see Migrate to Zenifra.
Keep the Vercel project running while you deploy and validate the application on Zenifra. Only remove the Vercel project after switching DNS.
What changes between the platforms
On Vercel, server code runs in functions that start on demand and scale to zero. On Zenifra, the application is a long-running server: a process that stays up, reuses database connections, and has no cold start per request.
| On Vercel | On Zenifra |
|---|---|
| Project | HTTP project |
| Next.js with per-route functions | One next start server with every route |
Vercel Functions in the api/ folder | Routes of an HTTP server (Express, Fastify, Hono, etc.) |
Cron Jobs in vercel.json | Scheduled jobs |
| Preview Deployments | Preview Environments |
| Deployment Protection | IP access control or protection inside the application |
| Marketplace Postgres and KV (Neon, Upstash, etc.) | Managed PostgreSQL and Managed cache |
| Vercel Blob | Armazém |
1. Copy the settings from Vercel
In the Vercel dashboard, open the project and click Settings.
Build and Deployment
In Settings › Build and Deployment, write down the fields in the Build & Development Settings section and the sections below it:
| Vercel field | What it does |
|---|---|
| Framework Preset | Detected framework, such as Next.js, Vite, or Other |
| Build Command | Build command. If Override is off, it is the framework default, usually npm run build |
| Output Directory | Published folder for static sites, such as dist or build |
| Install Command | Dependency installation, such as npm install or pnpm install |
| Root Directory | Application folder inside the repository (monorepo) |
| Node.js Version | Node.js major version, such as 22.x or 24.x |
If package.json has engines.node, that version takes precedence over the Node.js Version field: use the one from package.json.
Production branch and domains
- In Settings › Environments › Production, the Branch Tracking section shows the branch deployed to production, usually
main. - In Settings › Domains, note every domain of the project.
- In Settings › Git, check the connected repository.
If your domains use Vercel nameservers (ns1.vercel-dns.com and ns2.vercel-dns.com), also copy every DNS record, such as e-mail MX and TXT, before changing the nameservers. Otherwise the domain's e-mail may stop working.
Environment Variables
In Settings › Environment Variables, each variable has a Value, a Type, and the environments where it applies: Production, Preview, or Development. Copy the Production ones.
The fastest way is to export them with the Vercel CLI, in the project folder:
vercel env pull .env.production --environment=productionWithout --environment=production, the CLI downloads the Development variables. Check the generated file before using it.
Secret variables (formerly called Sensitive) cannot be read after they are saved, neither in the dashboard nor with the CLI. Get those values from their source, such as the payment provider's dashboard or the team's password manager, or generate new ones.
Also check the team's shared variables in Team Settings, which reach the project without showing up in its list.
vercel.json
If the repository has a vercel.json (or vercel.ts), write down the keys below. Zenifra does not read this file, so each one needs an equivalent:
| Key | What to do on Zenifra |
|---|---|
buildCommand, installCommand, outputDirectory | Use the values in the project commands; see step 2 |
rewrites, redirects, headers | Move to next.config or to the file server; see Rewrites, redirects, and headers |
cleanUrls, trailingSlash | Same path as redirects |
crons | Create scheduled jobs |
functions (maxDuration, memory) | Not applicable: the application is a long-running server and resources come from the plan |
regions | Not applicable: Zenifra runs in Brazil |
images | Use images in next.config |
2. Create the project on Zenifra
In the console, click + Create project, choose HTTP Application and the plan. Under Advanced Settings, choose Git repository as the Project Source, the Git provider GitHub (or Forgejo), the same repository, and the production branch. Then fill in the fields for your project type.
Next.js
| On Vercel | In the Zenifra console |
|---|---|
| Node.js Version | Runtime Node.js and the same Version (20, 22, 24, or 26) |
| Root Directory | Root directory. Keep . if the field was empty |
| Install Command | No field: Zenifra installs with npm ci |
| Build Command | Build Command: npm run build |
| — | Start Command: npx next start -H 0.0.0.0 -p 3000 |
| — | Port: 3000 |
| Environment Variables | Environment Variables, including NEXT_PUBLIC_* |
Server rendering, API routes, Server Actions, middleware (or proxy.ts in Next.js 16), and image optimization with next/image work with next start, with no adapter. See the full Next.js guide.
Static site or SPA (Vite, React, Vue, Angular, Astro)
| On Vercel | In the Zenifra console |
|---|---|
| Node.js Version | Runtime Node.js and the same Version |
| Build Command | Build Command, such as npm run build |
| Output Directory | Folder used in the Start Command |
| — | Start Command: npx serve -s dist -l tcp://0.0.0.0:3000, replacing dist with the Output Directory |
| — | Port: 3000 |
Add serve to the dependencies with npm install serve. For multi-page HTML sites, such as Astro, remove -s. To spend less, serve the folder with NGINX on the Static plan; see Static sites and SPAs.
Vercel Functions outside Next.js
In projects that are not Next.js, each file in the api/ folder becomes a function on Vercel. On Zenifra, those functions become routes of an HTTP server that stays up. An example with Express:
import express from 'express'
import hello from './api/hello.js'
const app = express()
app.use(express.json())
// Each file in api/ becomes a route
app.all('/api/hello', (req, res) => hello(req, res))
app.listen(process.env.PORT || 3000, '0.0.0.0')Functions in the handler(req, res) format usually work unchanged in Express. Functions that export GET or fetch with Web Request and Response fit Hono better. If the project also has a static frontend, serve the build folder from the same server with express.static, or create two projects: one for the API and one for the site.
Set Start Command node server.js, Port 3000, and the variable PORT=3000.
Install Command with pnpm, Yarn, or Bun
Zenifra installs Node.js dependencies with npm ci and needs a committed package-lock.json. If Vercel uses pnpm or Yarn, generate and commit a package-lock.json before migrating, or deploy as an OCI image. Bun projects can use the Bun Runtime, which installs with bun install --frozen-lockfile. See Runtimes.
3. Adjust what differs between the platforms
Vercel variables
Variables created by Vercel, such as VERCEL_URL, VERCEL_ENV, VERCEL_PROJECT_PRODUCTION_URL, and VERCEL_GIT_COMMIT_SHA, do not exist on Zenifra. Search the code and replace them with your own variables:
grep -rn "VERCEL_" --include=*.{js,ts,tsx,jsx,mjs} .For example, replace VERCEL_URL with an APP_URL variable holding the project's Zenifra URL or your domain. Remember that VERCEL_URL had no https://; check whether the code added the protocol.
Variables during the build
On Zenifra, project variables are available during the build, so NEXT_PUBLIC_* and VITE_* work as on Vercel. After changing one of them, publish again, because the value is written into the JavaScript. See Variables during the build.
Rewrites, redirects, and headers
- Next.js: move
rewrites,redirects, andheadersfromvercel.jsonto the functions with the same names innext.config. In redirects,permanent: truestill returns308. - Static site with
serve:-salready handles the SPA rewrite toindex.html. For other rules, create aserve.jsoninside the published folder withrewrites,redirects, andheaders. - Static site with NGINX: use
rewrite,return 301, andadd_headerinnginx.conf. See the example in Static sites and SPAs.
Cron Jobs
On Vercel, a Cron Job sends a GET request to a route of your application, with the CRON_SECRET secret in the Authorization header. On Zenifra, a scheduled job runs a command and exits. To keep the route you already have, create a script that calls it:
const res = await fetch(process.env.CRON_URL, {
headers: { authorization: `Bearer ${process.env.CRON_SECRET}` },
})
if (!res.ok) process.exit(1)Create a Scheduled job with Task source GitHub Repository, Runtime Node.js, Task command node scripts/cron.mjs, and the variables CRON_URL (the route's full URL) and CRON_SECRET. The Cron expression can be the same as in vercel.json: both platforms use UTC.
If the task does not depend on the application, run the logic directly in the job script, without going through the route.
Edge Runtime
Routes with export const runtime = 'edge' run on the same Node.js server on Zenifra. Remove that line: Next.js itself recommends the Node.js runtime, and recent versions no longer accept edge.
Next.js cache with multiple instances
ISR and the Next.js data cache live on each instance's disk. With one instance, they work as expected. With more than one, each instance has its own cache, and revalidatePath or revalidateTag only affect the instance that received the call. If that matters, use one instance or configure a shared cacheHandler with the managed cache. See Next.js cache and multiple instances.
User uploads
On Zenifra, the instance disk is wiped on every deploy, just like on Vercel. If the application uses Vercel Blob, move the files to Armazém, which is S3-compatible, or keep Blob during the transition.
4. Migrate databases and services
Vercel Marketplace databases belong to the source provider, such as Neon, Supabase, or Upstash. Export the data directly from it:
| Source | Destination on Zenifra | How to migrate |
|---|---|---|
| Postgres (Neon, Supabase, Prisma Postgres) | Managed PostgreSQL | pg_dump and pg_restore; see Migrate the database |
| KV / Redis (Upstash) | Managed cache or Key-Value | Cache data can be rebuilt by the application |
| Vercel Blob | Armazém | Download the files and upload them with the AWS CLI or the S3 SDK; see Connect applications |
Create the databases before the application and enter the new connection URLs, such as DATABASE_URL, in the project variables. Connections to Zenifra PostgreSQL require TLS.
5. Validate and switch DNS
- Open the project's
*.clients.zenifra.comURL and test login, main pages, API routes, forms, and webhooks. - Check Build logs and the application logs for errors.
- Update external webhooks (payments, authentication, e-mail) and OAuth callback URLs to the new address.
- Follow the switch-day checklist: lower the DNS TTL, run the final data copy, add the domain on Zenifra, and update DNS.
- Keep the Vercel project running for a few days for rollback, and only then remove it.
Common issues
| Symptom | Likely cause | Fix |
|---|---|---|
npm ci fails during the build | Project uses pnpm or Yarn, without package-lock.json | Generate and commit a package-lock.json, or use the Bun runtime if applicable |
/api/... route returns 404 | Function from the api/ folder without a server | Register the route in the HTTP server; see Vercel Functions outside Next.js |
| Public URL does not respond | Server listening on localhost or on another port | Listen on 0.0.0.0 and use the same port in the Port field |
Links and e-mails point to vercel.app | Code uses VERCEL_URL | Replace it with your own variable, such as APP_URL |
A vercel.json redirect stopped working | Zenifra does not read vercel.json | Move the rule to next.config, serve.json, or nginx.conf |
| Reloaded SPA route returns 404 | Missing fallback to index.html | Use serve -s or try_files in NGINX |
| Cron does not run | vercel.json Cron Jobs are not read | Create a scheduled job |
Need help?
Write to [email protected] with the fields you copied from Vercel, or reach us on WhatsApp at +55 (11) 5199-3013.
Last updated on
Migrate to Zenifra
Bring apps and databases from Heroku, Vercel, Netlify, Render, Railway, Fly.io, or a VPS to Zenifra with a step-by-step plan, platform equivalents, and data migration.
Migrate from Heroku to Zenifra
Step-by-step guide to bring a Heroku app to Zenifra: how to export Config Vars, translate the Procfile, release phase, buildpacks, and Heroku Scheduler, migrate Heroku Postgres, and where to enter each value in the console.