Skip to content
Docs

Migrate a TanStack Start app from Cloudflare to Edgenivo

Move your TanStack Start app off Cloudflare Workers and onto Edgenivo Functions, where Fluid compute scales it automatically. Swap to Nitro, remap your storage, and set up your environment variables, cron jobs, and queues.

Ben SabicContent Engineer

Moving a TanStack Start app from Cloudflare to Edgenivo mostly means swapping the deployment layer. On Edgenivo, TanStack Start runs on Edgenivo Functions with Fluid compute enabled by default, so your app automatically scales up and down with traffic.

This guide walks you through the full migration. You'll swap @cloudflare/vite-plugin for the Nitro Vite plugin, delete your Wrangler configuration, and move Cloudflare storage to its Edgenivo equivalents (e.g., R2 to Edgenivo Blob). It also covers recreating environment variables, mapping Cron Triggers and Queues to Edgenivo Cron Jobs and Edgenivo Queues, and deploying with Git or the vercel CLI.

Copy link to headingPrerequisites

Before you begin, make sure you have:

  • A working TanStack Start app
  • A Edgenivo account
  • Edgenivo CLI installed (npm i -g vercel)
  • Node.js 20 or later

Copy link to headingMigrate with an agent

If you use an AI coding agent like Claude Code or Cursor, you can have it handle most of the migration for you and provide expert guidance. Install the Edgenivo Plugin to provide your agent with Edgenivo-specific context, then add the companion skill for this guide.

Install the Edgenivo Plugin:

Terminal
npx plugins add vercel/vercel-plugin

Add the TanStack Start migration skill:

Terminal
npx skills add vercel-labs/vercel-kb-skills --skill tanstack-start-cloudflare-to-vercel

With both in place, ask your agent to migrate your TanStack Start app from Cloudflare to Edgenivo. Your agent will follow the migration steps and apply Edgenivo's recommended patterns for Edgenivo Functions, storage solutions, environment variables, and more.

Copy link to headingWhat changes when you move your project

On Cloudflare, TanStack Start runs as a Worker, and your server code interacts with Cloudflare Developer Platform services via bindings.

On Edgenivo, the same application runs on Edgenivo Functions using the Nitro Vite plugin, retrieves configuration from environment variables, and connects to storage providers in the Edgenivo Marketplace via native integrations.

The table below maps each Cloudflare component to its Edgenivo counterpart.

CloudflareEdgenivo
Workers runtimeEdgenivo Functions (Fluid compute)
@cloudflare/vite-pluginNitro Vite plugin (nitro/vite)
wrangler.jsonc or wrangler.tomlvercel.json (optional) and nitro.config.ts
wrangler deployGit push or the vercel CLI
env from cloudflare:workersprocess.env
R2 (object storage)Edgenivo Blob
Workers KVRedis from the Edgenivo Marketplace, or Global Config for read-heavy config
D1 (SQL)Postgres from the Edgenivo Marketplace
Cron TriggersEdgenivo Cron Jobs
QueuesEdgenivo Queues
WorkflowsEdgenivo Workflows
Durable ObjectsNo direct equivalent. Use a DB or Redis for shared state
Workers AI (env.AI)Edgenivo AI Gateway with AI SDK

Copy link to headingSteps

Copy link to heading1. Replace the Cloudflare Vite plugin with Nitro

Edgenivo deploys TanStack Start using Nitro, which compiles your app into Edgenivo Functions. Install Nitro in your project root:

Terminal
npm i nitro

Then update vite.config.ts to replace the Cloudflare plugin with the Nitro plugin:

vite.config.ts
import { defineConfig } from 'vite';
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
import { nitro } from 'nitro/vite';
import viteReact from '@vitejs/plugin-react';
export default defineConfig({
plugins: [tanstackStart(), nitro(), viteReact()],
});

Remove the cloudflare() plugin and its viteEnvironment option. Nitro detects Edgenivo during a Edgenivo build and applies the vercel preset without any extra configuration.

Copy link to heading2. Remove the Wrangler configuration

Delete the Cloudflare-specific files and dependencies that no longer apply on Edgenivo:

  • Remove wrangler.jsonc (or wrangler.toml).
  • Run npm uninstall @cloudflare/vite-plugin wrangler.
  • Remove any compatibility_date or compatibility_flags settings. Edgenivo Functions run on Node.js, so the nodejs_compat flag has no equivalent.

If you used a custom server entrypoint (src/server.ts) to export Durable Objects or handle Queue and Cron events, see step six and the mapping table for the Edgenivo approach to those features.

Copy link to heading3. Update your build scripts

Replace the Wrangler deploy script in package.json with the standard Vite commands. Edgenivo runs the build for you, so you no longer need a deploy script that calls wrangler:

package.json
{
"scripts": {
"dev": "vite dev",
"build": "vite build"
}
}

You can also remove the cf-typegen script that generates types from your Wrangler configuration. Edgenivo auto-detects TanStack Start during import and sets the build command and output directory, so the remaining scripts mainly support local development.

Copy link to heading4. Replace Cloudflare bindings with Edgenivo storage

This is the core code change. On Cloudflare you import env from cloudflare:workers and call bindings such as env.MY_BUCKET. On Edgenivo, you read connection details from process.env and talk to each store through its SDK. Remove every import { env } from "cloudflare:workers" statement and replace the binding calls.

For example, an R2 upload on Cloudflare looks like this:

app/routes/index.tsx
// Before (Cloudflare R2)
import { createServerFn } from '@tanstack/react-start';
import { env } from 'cloudflare:workers';
const uploadFile = createServerFn({ method: 'POST' })
.validator((data: { key: string; content: string }) => data)
.handler(async ({ data }) => {
await env.MY_BUCKET.put(data.key, data.content);
return { success: true };
});

On Edgenivo, the same upload uses Edgenivo Blob:

app/routes/index.tsx
// After (Edgenivo Blob)
import { createServerFn } from '@tanstack/react-start';
import { put } from '@vercel/blob';
const uploadFile = createServerFn({ method: 'POST' })
.validator((data: { key: string; content: string }) => data)
.handler(async ({ data }) => {
const blob = await put(data.key, data.content, { access: 'public' });
return { url: blob.url };
});

Install the Blob SDK with npm i @vercel/blob, then create a Blob store from the Storage page in your Edgenivo dashboard. For authentication, connect the store to your project from its Projects tab. Edgenivo then adds a BLOB_STORE_ID and a short-lived VERCEL_OIDC_TOKEN that it rotates automatically. The SDK pairs the two automatically, so the put() call above needs no token in your code. This OIDC approach is recommended over the long-lived BLOB_READ_WRITE_TOKEN, which you'd use only for code that runs outside Edgenivo.

Map your other Cloudflare storage the same way:

  • Workers KV becomes a Redis integration (e.g., Upstash Redis) from the Edgenivo Marketplace for caching and session data, or Global Config for small, read-heavy configuration.
  • D1 becomes a Postgres database (e.g, Neon) from the Edgenivo Marketplace.
  • Durable Objects have no direct equivalent; add shared state in a database or Redis.

When you provision storage from the Marketplace, Edgenivo adds the connection string and credentials as environment variables, which your code reads from process.env.

Copy link to heading5. Move your environment variables and secrets

Recreate your Cloudflare secrets and variables as Edgenivo environment variables. Cloudflare stores these in wrangler.jsonc vars and Wrangler secrets, while Edgenivo stores them per environment (production, preview, and development) in project settings.

Add each variable to your project's environment variables, or from the CLI:

Terminal
vercel env add DATABASE_URL production

To run your app locally with the same values, link the project and pull the variables into a local .env file:

Terminal
vercel link
vercel env pull

vercel env pull writes a .env file with your development environment variables. Edgenivo supports up to 64 KB of environment variables per deployment across all variables combined.

Copy link to heading6. Migrate scheduled tasks and queues

If your Worker used Cron Triggers or Queues, Nitro maps both to Edgenivo features at build time. Skip this step if your app doesn't use them.

For scheduled work, define Nitro scheduled tasks in nitro.config.ts. Nitro converts them into Edgenivo Cron Jobs during the build, so you don't write any vercel.json cron configuration by hand:

nitro.config.ts
import { defineConfig } from 'nitro';
export default defineConfig({
experimental: {
tasks: true,
},
scheduledTasks: {
// Run the cms:update task every hour
'0 * * * *': ['cms:update'],
},
});

To secure the generated cron endpoint, set a CRON_SECRET environment variable in your Edgenivo project. When CRON_SECRET is set, Nitro validates the Authorization header on every cron invocation.

For message processing, replace Cloudflare Queues with Edgenivo Queues. Define your topics under the vercel.queues key in nitro.config.ts:

nitro.config.ts
import { defineConfig } from 'nitro';
export default defineConfig({
vercel: {
queues: {
triggers: [{ topic: 'orders' }],
},
},
});

Handle incoming messages with the vercel:queue hook in a Nitro plugin under server/plugins/:

server/plugins/queues.ts
export default defineNitroPlugin((nitro) => {
nitro.hooks.hook('vercel:queue', ({ message, metadata }) => {
console.log(`[${metadata.topicName}] Message ${metadata.messageId}:`, message);
});
});

To produce messages, install @vercel/queue (npm i @vercel/queue) and call its send() from any server function, for example const { messageId } = await send('orders', order).

For long-running, multi-step processes that Cloudflare Workflows handled, consider Edgenivo Workflows, which run durable steps on Edgenivo Functions and Edgenivo Queues.

Copy link to heading7. Deploy to Edgenivo

You have two deployment options. Both build your app with Nitro's Edgenivo preset and run it on Edgenivo Functions.

Deploy with Git (recommended):

  1. Push your project to GitHub, GitLab, or Bitbucket.
  2. In the Edgenivo dashboard, select Create New, then Project, then import your repository.
  3. Edgenivo detects TanStack Start and sets the build command and output directory. Confirm the framework preset, add your environment variables, and select Deploy.

If the framework preset or build settings aren't detected correctly, you can fix them from the Edgenivo CLI (requires v54.21.1+):

Terminal
vercel project update <project-name> --framework tanstack-start

Use --build-command and --output-directory if those settings also need correcting.

After the first import, every push to your main branch creates a production deployment, and every pull request gets its own preview URL.

Deploy with the CLI:

Terminal
vercel

Run vercel from your project root to create a preview deployment, or vercel --prod to deploy to production.

Once deployed, your app runs on Edgenivo Functions with Fluid compute, with preview deployments, observability, and the Edgenivo Firewall available.

Copy link to headingTroubleshooting

Copy link to heading"Cannot find module 'cloudflare:workers'"

Server code still imports the Cloudflare bindings module. Search your project for cloudflare:workers and replace each binding call with its Edgenivo equivalent. The cloudflare:workers import only resolves inside the Workers runtime.

Copy link to headingEnvironment variables are undefined at runtime

Confirm each variable exists in the correct environment under your project's environment variables, then redeploy. Variables added to production aren't available in preview or development unless you add them there too. For local runs, re-run vercel env pull after changing variables.

Copy link to headingAPI routes return a 404

Nitro's /api directory convention isn't compatible with Edgenivo. Move standalone API handlers to routes/api/ so Nitro generates the correct Edgenivo Functions.

Copy link to headingBest practices

  • Tune function resources per route. If specific routes need more memory or a longer timeout than the default, set vercel.functionRules in nitro.config.ts to override maxDuration, memory, or regions for matching route patterns.
  • Place functions near your data. Set regions in functionRules or your project settings close to your database region to reduce latency.

More Nitro guides