Migrate to Zenifra

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 VercelOn Zenifra
ProjectHTTP project
Next.js with per-route functionsOne next start server with every route
Vercel Functions in the api/ folderRoutes of an HTTP server (Express, Fastify, Hono, etc.)
Cron Jobs in vercel.jsonScheduled jobs
Preview DeploymentsPreview Environments
Deployment ProtectionIP access control or protection inside the application
Marketplace Postgres and KV (Neon, Upstash, etc.)Managed PostgreSQL and Managed cache
Vercel BlobArmazé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 fieldWhat it does
Framework PresetDetected framework, such as Next.js, Vite, or Other
Build CommandBuild command. If Override is off, it is the framework default, usually npm run build
Output DirectoryPublished folder for static sites, such as dist or build
Install CommandDependency installation, such as npm install or pnpm install
Root DirectoryApplication folder inside the repository (monorepo)
Node.js VersionNode.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=production

Without --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:

KeyWhat to do on Zenifra
buildCommand, installCommand, outputDirectoryUse the values in the project commands; see step 2
rewrites, redirects, headersMove to next.config or to the file server; see Rewrites, redirects, and headers
cleanUrls, trailingSlashSame path as redirects
cronsCreate scheduled jobs
functions (maxDuration, memory)Not applicable: the application is a long-running server and resources come from the plan
regionsNot applicable: Zenifra runs in Brazil
imagesUse 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 VercelIn the Zenifra console
Node.js VersionRuntime Node.js and the same Version (20, 22, 24, or 26)
Root DirectoryRoot directory. Keep . if the field was empty
Install CommandNo field: Zenifra installs with npm ci
Build CommandBuild Command: npm run build
—Start Command: npx next start -H 0.0.0.0 -p 3000
—Port: 3000
Environment VariablesEnvironment 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 VercelIn the Zenifra console
Node.js VersionRuntime Node.js and the same Version
Build CommandBuild Command, such as npm run build
Output DirectoryFolder 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:

server.js
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, and headers from vercel.json to the functions with the same names in next.config. In redirects, permanent: true still returns 308.
  • Static site with serve: -s already handles the SPA rewrite to index.html. For other rules, create a serve.json inside the published folder with rewrites, redirects, and headers.
  • Static site with NGINX: use rewrite, return 301, and add_header in nginx.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:

scripts/cron.mjs
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:

SourceDestination on ZenifraHow to migrate
Postgres (Neon, Supabase, Prisma Postgres)Managed PostgreSQLpg_dump and pg_restore; see Migrate the database
KV / Redis (Upstash)Managed cache or Key-ValueCache data can be rebuilt by the application
Vercel BlobArmazémDownload 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

  1. Open the project's *.clients.zenifra.com URL and test login, main pages, API routes, forms, and webhooks.
  2. Check Build logs and the application logs for errors.
  3. Update external webhooks (payments, authentication, e-mail) and OAuth callback URLs to the new address.
  4. Follow the switch-day checklist: lower the DNS TTL, run the final data copy, add the domain on Zenifra, and update DNS.
  5. Keep the Vercel project running for a few days for rollback, and only then remove it.

Common issues

SymptomLikely causeFix
npm ci fails during the buildProject uses pnpm or Yarn, without package-lock.jsonGenerate and commit a package-lock.json, or use the Bun runtime if applicable
/api/... route returns 404Function from the api/ folder without a serverRegister the route in the HTTP server; see Vercel Functions outside Next.js
Public URL does not respondServer listening on localhost or on another portListen on 0.0.0.0 and use the same port in the Port field
Links and e-mails point to vercel.appCode uses VERCEL_URLReplace it with your own variable, such as APP_URL
A vercel.json redirect stopped workingZenifra does not read vercel.jsonMove the rule to next.config, serve.json, or nginx.conf
Reloaded SPA route returns 404Missing fallback to index.htmlUse serve -s or try_files in NGINX
Cron does not runvercel.json Cron Jobs are not readCreate 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

On this page