Migrate to Cloudflare
Automate your move from Vercel and Railway to Cloudflare Pages & Workers with Clodo’s mapping, scaffolding, and validation toolkit.
What gets migrated
- Config: vercel.json/railway configs → wrangler.toml, routes, headers
- Framework: Next.js Pages/App Router → Pages + Next plugin or Workers
- Services: KV/Blob/Cron/Edge Config/Postgres → KV/R2/Cron/KV+DO/PG or D1
- Env & Secrets: exported, namespaced, and imported as Cloudflare secrets
- Data: KV copy and Blob sync tools with checksums
- Validation: route parity, SSR smoke tests, cache correctness
How it works
- Analyze your project and detect frameworks/services
- Generate Cloudflare artifacts and bindings
- Run data sync (optional) and deploy a preview
- Review parity report and finalize cutover
Below is a compact version of our migration playbook and capability model directly on this page.
Supported sources and targets
Sources (now and next)
- Vercel: Next.js (App/Pages), KV, Blob, Edge Config, Cron, Postgres
- Railway: Services (web/worker), PG/Redis, variables, domains
- Netlify (roadmap): redirects, functions, edge middleware, envs
- Render (roadmap): services, cron, disk flags
Targets
- Cloudflare Pages: Next.js plugin, functions/, headers.json, _routes.json
- Cloudflare Workers: Hono/itty router, Durable Objects, KV/R2/D1 bindings
Migration flow (CLI UX)
- Detect framework, middleware, routes, and services (vercel.json, next.config.js, package.json, env)
- Map services (KV → KV, Blob → R2, Edge Config → KV/DO, Cron → Triggers, PG → external PG or D1)
- Generate artifacts (wrangler.toml, _routes.json, headers.json, functions/, bindings)
- Produce a parity report with warnings and remediation steps
- Optionally provision resources, run preview deploy, smoke tests, and ship
Config mapping
- vercel.json → wrangler.toml: routes/rewrites/redirects to Pages/Workers routing or _routes.json; headers to headers.json or Workers handlers; env to [vars] + secrets
- next.config.js: images domains → Cloudflare Images/static fallback; experimental flags warned if unsupported
Framework mapping (Next.js)
- Pages Router: use Pages + Next plugin with minimal changes
- App Router: supported for many cases; warn on Node-only APIs in Server Actions
- Middleware: map to Pages/Workers middleware equivalents; validate edge-runtime compatibility
- ISR/SSG: revalidate via cache + Workers route or Pages functions; fallback SSG at build, dynamic via SSR
- API Routes: map to Pages Functions or Workers routes
Services mapping
- Vercel KV → Cloudflare KV: namespace mapping, TTL semantics, size limits, eventual consistency notes
- Vercel Blob → Cloudflare R2: public/private buckets, signed URLs, migration script with checksum
- Edge Config → KV/DO: hierarchical config with per-environment overrides
- Cron → Cloudflare Cron: schedule translation, prefixed names
- Postgres: keep external PG (e.g., Neon) via HTTP/Prisma for parity, or migrate to D1 where constraints fit
Runtime and polyfills
- Workers runtime lacks Node built-ins (fs, net, tls, some Buffer APIs)
- Auto-detect Node usage; suggest polyfills or alternatives
- Flag native/binary deps early; isolate via HTTP or replace with Cloudflare primitives
Images and optimization
- Next/Image optimizer → Cloudflare Images or static generation
- Pages: use CF Images loader; Workers: route to Images API
- Document cache-control differences and transform limitations
Caching strategy
- CDN defaults vs application-level strategies
- Utilities: cacheByRoute, cacheByHeader, tag revalidation
- KV-backed tag invalidation for SSR where needed
Environment & secrets
- Export Vercel env; import to Cloudflare via wrangler secrets with namespacing
- Map branch-based envs to CF environments (production, preview, dev)
Observability
- Replace Vercel Analytics with Cloudflare Analytics/Logs + Sentry/Logflare
- Request logging middleware, error boundaries, edge traces
Sample parity report
Summary: 84% auto-mapped, 6 warnings, 2 blockers
Routes: 51 pages mapped, 3 rewrites migrated, 1 custom header manual
Middleware: migrated (matcher adjusted)
Services: KV→KV done; Blob→R2 pending data copy
Runtime: node:crypto.randomUUID → use global crypto
Images: Next/Image → CF Images (update loader)
Action items: listed with code pointers
Validation & tests
- Route snapshot tests: pre/post responses for key paths
- SSR smoke tests: HTML markers, status codes, critical cookies
- Edge function tests: middleware contracts, headers, redirects
Data migration helpers
- KV copy (Vercel KV → CF KV) with concurrency + retry/backoff
- Blob sync (Vercel Blob → R2) with checksum verification
- DB export/import adapters for PG/D1; quota-aware, prepared statements
Known edge cases
- Node native modules or binary dependencies (e.g., sharp without CF Images)
- ISR patterns relying on FS cache; replace with KV/DO strategies
- On-demand revalidation with custom auth paths
- WebSockets beyond DO constraints; pivot to DO rooms/Queues
Rollout strategy
- Preview env dry run → compare metrics/errors
- Canary by domain or route path
- Clear rollback: DNS switchback, feature flag off
Capability architecture
A platform-agnostic importer powering Vercel/Railway/Netlify/Render migrations to Cloudflare.
Objectives
- Decouple sources via adapters; shared domain model
- Rule-driven, testable transformations
- Multiple targets (Pages, Workers) with consistent orchestration
Core capabilities
- Detection & discovery: identify platform, build project graph
- Parsers & domain model: App, Route, Service, Policy
- Mapping library: rules and severities (auto/manual/blocker)
- Transformers: config, code (codemods), env/secret mappers
- Generators: Pages/Workers structures, wrangler.toml bindings
- Orchestration: provision with safeguards, env alignment
- Validation: parity, SSR snapshots, performance checks
- Data tools: KV/Blob/DB migration pipelines
- Reporting: migration report with risk and effort
- Extensibility: source/target adapters, rule packs
Key interfaces
- ISourceAdapter: detect, parse, extract
- ITargetAdapter: plan, generate, provision, deploy
- Rule: applies(model) → transform(model)
- ParityReport: coverage %, auto/manual, blockers, risk
Security & delivery
- Secrets never stored in plaintext; OS keychain/CF secrets API
- PII redaction (opt-in) and audit logs for provisioning
- Delivery: OSS CLI core + commercial rule packs/support
Example end-to-end (Vercel → Pages)
- Detect Next.js; parse vercel.json; extract rewrites/headers
- Apply rules: KV→KV, Blob→R2, Edge Config→KV
- Generate: wrangler.toml, _routes.json, functions/api/*, Next plugin config
- Provision KV/R2/D1; map env; optional seed
- Validate smoke tests; produce parity report; deploy preview
Railway → Cloudflare notes
Concepts mapping
- Services (web/worker) → Pages or Workers
- Variables → wrangler.toml [vars] + secrets; env scoping mapped
- Domains → Cloudflare DNS/Pages custom domains
- Postgres → keep external PG or migrate to D1 (where feasible)
- Redis → KV/DO-based cache patterns
- Cron → Cloudflare Cron Triggers
- Persistent Disk → use R2 or external storage
Adapter actions
- Parse railway config via CLI; build service graph
- Generate Workers for APIs and Pages for frontends
- Create wrangler.toml bindings (KV, R2, D1, Queues, DO)
- Migrate env/secrets with namespacing and branch mapping
Edge cases & validation
- Native binaries, FS assumptions, stateful workloads
- Long-lived connections → DO rooms or Queues
- Probe health endpoints pre/post; export PG and sync blobs to R2
FAQ
Can I keep my existing Postgres?
Yes. Keeping external PG (e.g., Neon) via HTTP/Prisma is recommended for parity. You can migrate to D1 when your data model and traffic patterns fit.
What if my app uses Node-only APIs?
We flag Node built-ins and native modules. Often there are web-compatible alternatives or Cloudflare primitives; otherwise isolate behind HTTP microservices.
How do you validate parity?
We generate route snapshots, SSR smoke tests, and edge middleware tests. A parity report summarizes coverage, warnings, and blockers with code pointers.
Want the full docs? See the Migration directory on GitHub: docs/migration.