Make the application portable before provisioning its final home. This separates code and service compatibility failures from provider networking and server setup, which makes both testing and rollback easier to reason about.
Establish a plain Node.js baseline
Run a production build outside Vercel using next start or standalone output. Copy .next/static and public when using standalone output, bind the service only behind a reverse proxy, and confirm the process handles SIGTERM with enough drain time for in-flight work and after() callbacks.
Treat filesystem cache as a deliberate choice. A single persistent instance can use the default disk cache. Multiple or ephemeral instances need a durable shared cache, coordinated tag invalidation, a consistent Server Functions encryption key, and a deployment identifier.
Remove hidden platform coupling
Search code and configuration for Vercel SDKs, request headers, regions, cron declarations, Blob calls, analytics, and integration-provided variables. Record replacement ownership before changing code. A portable interface is useful only when its data model, access mode, retries, and failure behavior are also understood.
Scheduled work needs authentication, overlap protection, retries, and observable outcomes. Object storage needs an explicit public/private policy, migration verification, and a plan for old URLs. Never assume a similarly named service has identical semantics.
Compare behavior, not just status codes
Exercise the same commit on both environments. Verify HTML, headers, cookies, redirects, streamed responses, optimized images, revalidation, uploads, callbacks, and business events. Capture latency and errors, but also inspect whether writes, scheduled work, and external side effects happen exactly once.
Only after this baseline passes should the provider-specific cutover begin.