Netlify → Cloudflare Pages
Move a Netlify project to Cloudflare Pages while translating builds, environment values, redirects, headers, forms, functions, domains, access, and a measured rollback path.
Should you make this move?
Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.
Netlify
- Excellent frontend deployment ergonomics combine previews, forms, functions, and add-ons
- Managed deployments reduce infrastructure and release-management work
- Platform-specific services and bandwidth or build costs can become limiting
- Runtime assumptions, platform services, and pricing models shape the architecture
Cloudflare Pages
- Static sites deploy globally with simple previews and strong Cloudflare integration
- Managed deployments reduce infrastructure and release-management work
- Pages-specific workflows and Functions constraints can limit complex full-stack applications
- Runtime assumptions, platform services, and pricing models shape the architecture
Cloudflare Pages: Static sites deploy globally with simple previews and strong Cloudflare integration. This removes a major source-side concern: Platform-specific services and bandwidth or build costs can become limiting.
What you lose: Excellent frontend deployment ergonomics combine previews, forms, functions, and add-ons. What you inherit: Pages-specific workflows and Functions constraints can limit complex full-stack applications.
Jump to a section
Know the shape of the move.
This timeline assumes
- Profile: one Git-connected project with one production domain, at most 20,000 deploy files, no asset larger than 25 MiB, up to 20 environment variables, five serverless functions, two forms, and 500 redirects.
- The destination is Cloudflare Pages. A move to Workers Static Assets or a framework-specific Workers adapter requires a different runtime plan.
- You control the Git repository, Netlify owner account, Cloudflare account and zone, DNS, environment values, third-party APIs, and production monitoring.
- The Netlify project remains deployed and billable through the seven-day rollback window.
- Every Netlify-specific feature is assumed non-portable until it has an explicit Cloudflare implementation and production-like preview test.
What survives the move.
“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.
| Item | Outcome | Impact | What happens | Mitigation |
|---|---|---|---|---|
| Static build output | clean | low | A compatible build command and output directory can deploy to Cloudflare Pages, subject to Pages file-count, file-size, build-time, and framework limits. | Run the exact production build in a clean environment and compare file count, largest file, routes, and asset hashes. |
| Git-connected continuous deployment | clean | medium | Cloudflare Pages can connect to the Git repository and produce production and preview deployments, but branch controls and deploy hooks must be configured again. | Map production branch, preview rules, build watch paths, deploy hooks, and required checks explicitly. |
| _redirects file | partial | high | Cloudflare states that a Netlify _redirects file can move to Pages, but Pages supports fewer advanced conditions and limits the file to 2,000 static plus 100 dynamic rules. | Lint every rule against Pages support, move excess rules to Bulk Redirects, and test order, splats, placeholders, proxies, and status codes. |
| Redirects in netlify.toml | manual | critical | Cloudflare instructs users to convert netlify.toml redirects into a _redirects file. Netlify country, language, role, cookie, query, signed proxy, and domain-level behavior may not have a Pages equivalent. | Translate supported rules and implement unsupported routing with Cloudflare Redirect Rules, Bulk Redirects, or Workers after an explicit design review. |
| Custom response headers | partial | critical | Static header rules can move to a Pages _headers file, but Cloudflare does not apply that file to responses generated by Pages Functions; redirects also run before headers. | Move static rules, emit function and SSR headers in code, and compare security, cache, CORS, and content headers route by route. |
| Netlify Functions | manual | critical | Both products use a functions directory, but handler syntax, request context, runtime APIs, configuration, bundling, limits, and response objects differ. | Rewrite each function for Pages Functions or Workers, map secrets and bindings, and run contract tests with production-like requests. |
| Netlify Edge Functions | manual | critical | Netlify Edge Functions do not deploy as Pages Functions unchanged even though both are edge runtimes. | Rewrite middleware and edge routes for Workers semantics and verify ordering, geolocation, cookies, caching, and origin behavior. |
| Netlify Forms and submissions | lost | critical | Cloudflare explicitly says to remove data-netlify attributes and implement form handling with a Pages Function plus a database or external service. Existing submissions do not migrate automatically. | Export historical submissions, build a new handler and storage/notification path, add spam protection, and test success, validation, duplicate, and failure cases. |
| Environment variables and secrets | manual | critical | Netlify variables can have team/site scope, deploy-context values, and build/function scopes. Cloudflare values and bindings must be recreated with environment-specific ownership. | Export keys and contexts securely, never commit values, map build versus runtime access, rotate secrets after migration, and verify no preview receives production-only credentials. |
| Netlify build plugins and post-processing | lost | high | Netlify build plugins, snippet injection, post-processing, and plugin-provided configuration do not execute on Cloudflare Pages. | Replace each effect with framework code, build scripts, Cloudflare configuration, or an explicit decision to remove it. |
| Netlify Identity and role-gated routes | lost | critical | Cloudflare suggests Zero Trust for access management, but it is not a drop-in migration of Netlify Identity users, tokens, signup flows, or application roles. | Choose a destination identity system, export permitted user data, design account migration and password reset, and test authorization separately. |
| Deploy previews | partial | medium | Cloudflare Pages provides preview deployments, but URLs, access policy, branch behavior, environment values, and third-party allowlists change. | Configure preview branch rules and access, use non-production secrets, and update callback and allowlist URLs. |
| Large files and very large sites | partial | high | Cloudflare Pages documents 20,000 files on Free, up to 100,000 on eligible paid plans, and a 25 MiB maximum per asset. | Measure the built artifact before migration; move oversized assets to R2 or another designed store and enable the required paid-plan setting for higher file counts. |
| Historical deploys, analytics, logs, form entries, and audit data | lost | medium | Operational history remains in Netlify and is not imported into the new Cloudflare project. | Export required reports, submissions, logs, deploy identifiers, configuration, and billing records before account cleanup. |
| Netlify subdomain and platform URLs | lost | medium | The netlify.app hostname remains a Netlify resource; Cloudflare creates a different pages.dev hostname. | Keep the Netlify project during rollback and configure an intentional long-term redirect before eventual retirement if the hostname has traffic. |
Where each thing goes.
| Source | Destination | Method | Notes |
|---|---|---|---|
| Netlify production branch | Cloudflare Pages production branch | manual | Confirm branch protection, preview behavior, and who can trigger production. |
| Build command | Cloudflare Pages build command | automatic | Use the same command only after it succeeds in Cloudflare's build image with the mapped runtime and variables. |
| Publish directory | Cloudflare Pages build output directory | automatic | Compare the final directory path from the project base, especially in monorepos. |
| netlify.toml build settings | Pages project or Wrangler configuration | transform | Treat the chosen configuration source as authoritative and reconcile it with dashboard values. |
| Netlify _redirects | Pages _redirects | transform | Supported simple rules can transfer; verify order, limits, advanced conditions, and function-route exceptions. |
| netlify.toml redirects | _redirects, Bulk Redirects, Redirect Rules, or Worker routing | manual | Choose the Cloudflare layer based on count and feature support; do not mechanically flatten unsupported conditions. |
| Netlify headers | Pages _headers or function Response headers | transform | Function and SSR responses must set their own headers. |
| Netlify Function handler | Pages Function onRequest handler or Worker fetch handler | manual | Translate request, context, environment, routing, response, errors, logs, and platform API usage. |
| Netlify Forms | Pages Function plus durable storage and notifications | manual | Remove data-netlify and replace spam, validation, file, notification, and submission-management behavior. |
| Build-scope environment variable | Pages build variable | manual | Map production and preview values without exposing production secrets to untrusted previews. |
| Function-scope environment variable | Pages Function variable, secret, or binding | manual | Choose text variable, encrypted secret, KV, D1, R2, service, or other binding by actual runtime behavior. |
| Custom domain | Pages custom domain association plus DNS record | manual | Associate the domain in the Pages dashboard before pointing a CNAME; a manual CNAME alone can cause a 522. |
| Netlify access control | Cloudflare Access or application authentication | manual | Separate preview protection from end-user application identity. |
| Deploy hook | Cloudflare deploy hook or CI deployment | manual | Update every caller, shared secret, branch target, retry policy, and monitoring check. |
Make the move recoverable.
Create the source-of-truth backup
Capture enough Netlify state to rebuild or restore the known-good production deployment without relying on memory.
- Record the repository and commit, production branch, base directory, package manager, runtime versions, build command, publish directory, functions directory, plugins, deploy contexts, ignore rules, and build-image settings.
- Download or archive the repository, netlify.toml, _redirects, _headers, function and edge-function source, lockfile, and the known-good production artifact if available.
- Export the names and context/scope mapping of all environment variables; copy secret values only into the approved secret store, never the repository or work log.
- Inventory domains, DNS records, certificates, redirects, headers, forms and submissions, functions, scheduled/background jobs, identity, access, webhooks, deploy hooks, plugins, analytics, logs, add-ons, and billing.
- Record the current production deploy ID, URL, timestamp, commit, checksums for critical assets, and a critical-URL response/header baseline.
- Export historical form submissions and operational reports that must survive Netlify cleanup.
- Test rollback access by confirming an authorized operator can restore the domain routing and that the known-good Netlify deploy is healthy.
Proof to capture: A dated configuration and feature manifest, redacted environment key matrix, encrypted secret location, production deploy ID, source commit, URL/header baseline, DNS snapshot, export checksums, and measured rollback access check.
Create the Cloudflare preview build
Prove the framework build independently of production routing.
- Create the Pages project from the same repository and production branch while leaving the custom domain on Netlify.
- Set the exact base, build, output, runtime, package-manager, and environment configuration from the inventory.
- Build the recorded production commit and compare generated file count, largest asset, route list, and critical asset hashes.
- Protect preview access where required and record the pages.dev deployment URL and ID.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Translate redirects and headers
Preserve routing, security, CORS, and cache behavior within Cloudflare's supported layers.
- Copy supported _redirects rules; translate netlify.toml rules only after classifying conditions, rewrites, proxies, domains, and counts.
- Move static headers into _headers and put function or SSR response headers in code.
- Check Pages limits and route ownership; redirects and _headers do not apply normally to responses owned by Pages Functions.
- Run the complete baseline URL set and compare status, final URL, chain length, cache, security, CORS, content type, and robots headers.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Rewrite functions and forms
Replace Netlify runtime behavior with testable Pages Functions or Workers behavior.
- Write one contract per function: method, route, inputs, authentication, environment, side effects, response, headers, timeout, retries, logs, and failure behavior.
- Translate handlers to the chosen Cloudflare runtime and bind only the required secrets or services.
- Replace Netlify Forms with an explicit POST handler, validation, spam protection, storage, notification, privacy, and export path.
- Run success, validation, authentication, duplicate, timeout, upstream failure, and retry tests against preview.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Recreate environment and deployment operations
Keep production and preview behavior intentional and least-privileged.
- Create a key-only mapping from Netlify scope and context to Cloudflare build, preview, production, function, secret, or binding.
- Enter values through the approved dashboard or secret command and verify they never appear in build output, logs, or client bundles.
- Recreate deploy hooks, callback URLs, allowlists, access rules, alerts, log destinations, and status monitoring.
- Rotate credentials that were exposed to both platforms after the migration stabilizes.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
The things most likely to hurt.
These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.
Treating a successful build as platform parity
A static homepage can work while forms, functions, redirects, headers, identity, hooks, or environment-specific behavior fails.
- Consequence
- Production appears healthy until a user or integration reaches the missing feature.
- Mitigation
- Inventory every Netlify feature and require one destination owner and contract test for each.
Stop if: Any production-critical platform feature is unmapped or untested.
Copying unsupported redirect behavior
Cloudflare Pages does not support every Netlify redirect condition or rewrite and imposes rule limits.
- Consequence
- Users can reach the wrong locale, role, proxy, or application path, or important rules may be ignored.
- Mitigation
- Classify rules by feature and count, choose the correct Cloudflare layer, and compare the full route baseline.
Stop if: A rule relies on unsupported query, country, language, cookie, domain-level, or role behavior without a tested replacement.
Assuming _headers covers functions
Cloudflare documents that _headers rules do not apply to Pages Function responses.
- Consequence
- Security, cache, CORS, and content-type protections can disappear on dynamic routes.
- Mitigation
- Set headers in function code and contract-test every dynamic route.
Stop if: Any function response lacks its required security, cache, CORS, or content header.
Mis-scoping secrets between preview and production
Netlify deploy contexts and scopes do not map automatically to Cloudflare environments and bindings.
- Consequence
- Production credentials can leak to previews, or production functions can start with missing or test values.
- Mitigation
- Use a key-only mapping, least privilege, separate preview values, and a redaction scan of bundles and logs.
Stop if: A production-only value is available to an untrusted preview or any runtime key is missing.
Pointing DNS before associating the Pages domain
Cloudflare warns that manually pointing a CNAME at pages.dev without first associating the custom domain can return a 522.
- Consequence
- The public domain can become unavailable during cutover.
- Mitigation
- Complete the Pages custom-domain workflow first, confirm readiness, then change the recorded DNS record.
Stop if: The domain is not active or ready in Pages, certificate issuance is blocked, or CAA prevents issuance.
Exceeding Pages artifact limits
Pages documents file-count, 25 MiB single-file, build-time, redirect, and header-rule limits.
- Consequence
- Builds can fail or large assets and rules can be omitted.
- Mitigation
- Measure the production artifact and configuration before project creation and choose R2, paid limits, Bulk Redirects, or Functions where required.
Stop if: The built artifact or configuration exceeds the selected Pages plan and no approved alternative exists.
Do the work in this order.
- Day 1 · inventory-backup
Inventory Netlify and prove rollback access
3–5 hours active1 day elapsedAllow report and submission exports to finish waiting- Capture build, repository, artifact, environment, runtime, routing, domain, feature, integration, access, monitoring, and billing state.
- Classify every Netlify-specific feature as direct, translate, rebuild, replace, or retire.
- Confirm the known-good Netlify deploy and domain rollback path.
Stop / go checkpointIs every production behavior accounted for?
Go when: The feature inventory has no unknown owner and Netlify can be restored without changing source code.
Stop when: An undocumented function, form, identity flow, plugin, hook, secret, or redirect remains.
- Day 2 · pages-preview
Build the same commit on Pages
2–4 hours active1 day elapsed30–90 minutes for build and preview cycles waiting- Create the Pages project, configure build settings and safe preview values, and deploy the recorded production commit.
- Measure files, asset sizes, route output, build warnings, and critical asset hashes.
- Protect preview access and update test-only third-party allowlists.
Depends on: inventory-backup
Stop / go checkpointIs the artifact equivalent and within limits?
Go when: The clean Pages build matches the expected artifact and all plan limits are satisfied.
Stop when: Files, assets, routes, runtime, or build warnings differ without explanation.
- Days 3–4 · translate-platform
Translate routing, runtime, forms, and operations
4–10 hours active1–2 days elapsedAllow external callback, secret, and access-policy updates to propagate waiting- Translate redirects and headers into the correct Cloudflare layers.
- Rewrite and contract-test functions, edge behavior, forms, identity, plugins, hooks, and integrations.
- Map variables, secrets, bindings, preview controls, logs, alerts, and deploy operations.
Depends on: pages-preview
Stop / go checkpointDoes preview satisfy every feature contract?
Go when: Every inventory row has a passing automated or manual acceptance result.
Stop when: Any critical runtime behavior, side effect, secret, access control, or failure path is untested.
- Day 5 · parity-rehearsal
Run parity checks and rehearse routing
2–4 hours active1 day elapsedObserve preview for at least four hours under production-like checks waiting- Run URL, redirect, header, asset, function, form, authentication, analytics, webhook, and performance checks.
- Associate the custom domain in Pages without moving public traffic and resolve CAA or certificate blockers.
- Rehearse and time the exact DNS cutover and rollback checklists.
Depends on: translate-platform
Stop / go checkpointCan cutover and rollback fit the window?
Go when: All blocking parity checks pass and both routing paths are timed with working credentials.
Stop when: The Pages domain is not ready or any operator, credential, baseline, or monitoring path is missing.
- Day 6 · cutover
Deploy the final commit and move the domain
2–3 hours active2–4 hours elapsedObserve DNS, certificate, edge cache, and third-party callbacks during the window waiting- Freeze configuration, deploy the final commit, and run blocking checks on pages.dev.
- Change the recorded domain routing only after Pages shows the domain ready.
- Run production checks twice and monitor errors, logs, submissions, and external callbacks.
Depends on: parity-rehearsal
Stop / go checkpointKeep Cloudflare live or restore Netlify?
Go when: Every production blocking check passes twice and real form/function/analytics receipts are confirmed.
Stop when: A blocking check fails or cannot be corrected and reverified within 60 minutes.
- Days 7–12 · monitor
Monitor through the rollback window
20–30 minutes daily activeSeven days after cutover elapsedSeven-day observation period waiting- Review availability, errors, 404s, redirects, functions, forms, authentication, cache, analytics, and billing.
- Compare production baselines and investigate user or integration reports.
- Approve cleanup only after the signed report and source-retirement review.
Depends on: cutover
Stop / go checkpointCan Netlify be retired?
Go when: Seven stable days pass, no rollback trigger remains, and all operational owners accept Cloudflare.
Stop when: Critical failures, lost submissions, missing traffic, security regressions, or unexplained costs remain.
Cut over with a way back.
Cutover
Move the production domain to the final verified Pages deployment while preserving a one-change rollback to Netlify.
- Freeze repository merges and platform configuration; record UTC time, final commit, Netlify deploy ID, and Cloudflare deployment ID.
- Deploy the final commit to Pages and run all blocking checks on the pages.dev hostname with production configuration.
- Confirm the custom domain is associated and ready in Pages, certificate and CAA requirements pass, and the before-state DNS record is recorded.
- Change only the required domain record or origin route; do not delete the Netlify domain or project.
- Run production checks twice from outside the operator network, including real safe form, function, webhook, analytics, redirect, header, and access tests.
- Monitor both platform logs and public synthetic checks for at least two hours before announcing completion.
Proof to capture: Freeze timestamp, commit and deployment IDs, before/after DNS records, Pages domain-ready state, two passing reports, form/function receipts, analytics event, external callback confirmation, and named operator approval.
Rollback
Restore the recorded Netlify production deploy and domain route without losing Cloudflare incident evidence or user submissions.
- Declare rollback, pause further Cloudflare configuration changes, and preserve deployment, function, request, form, and error logs.
- Restore the exact recorded DNS or origin route to the still-active Netlify custom domain.
- Run the critical URL, redirect, header, function, form, identity, analytics, and webhook baseline against Netlify.
- Export and reconcile any Cloudflare-only form submissions, writes, queues, or external side effects before reopening normal operations.
- Communicate the rollback owner, cause, restored deploy ID, evidence location, and next decision time.
Proof to capture: The production domain serves the recorded Netlify deploy, all baseline checks pass, post-cutover writes are reconciled, and only Netlify receives new production traffic.
- Availability, SSL, DNS, redirect, header, function, form, identity, analytics, or webhook blocking checks fail after one correction attempt.
- Production secrets are missing, exposed to previews, or present in client output.
- User submissions or state-changing requests are lost, duplicated, or cannot be reconciled.
- A critical regression cannot be corrected and fully reverified within 60 minutes.
- Unexpected error rate or cost exceeds the agreed threshold.
Prove the migration worked.
Every blocking check must pass. Capture the evidence before cleanup begins.
| Pass | ID | Check | Method | Expected result | Evidence |
|---|---|---|---|---|---|
BLD-01Blocking | Final artifact parity and limits | Compare final commit, build command, route list, file count, largest file, critical asset hashes, and warnings. | The intended commit builds cleanly; output is explained and within selected Pages limits. | Attach build logs and artifact comparison. | |
URL-01Blocking | Critical URL response parity | Request the baseline URL set against Netlify and Cloudflare; compare status, final URL, chain, body marker, and timing. | Every route has the intended result with no unexplained 404, loop, chain, or rewrite difference. | Attach the side-by-side URL report. | |
HDR-01Blocking | Header parity | Compare cache, security, CORS, content type, content encoding, robots, canonical-link, and custom headers on static and function routes. | Every required header is present once with deliberate Cloudflare-specific differences documented. | Attach raw response headers for the route matrix. | |
RDR-01Blocking | Rule behavior and limits | Test every static rule and representative dynamic, splat, placeholder, proxy, conditional, and domain case. | Rules resolve once to the approved destination; unsupported Netlify behavior has a tested replacement. | Attach the redirect test output and rule-count summary. | |
FUN-01Blocking | Runtime contract suite | Run success, validation, authentication, method, timeout, upstream failure, side-effect, retry, and CORS cases for every function. | Responses, headers, logs, side effects, and failure behavior meet the recorded contract. | Attach test results and redacted log/request IDs. | |
FRM-01Blocking | Submission lifecycle | Submit valid, invalid, duplicate, spam-like, and upstream-failure cases through every production form. | Valid data is stored and notified once; invalid or abusive data is rejected; failure is visible and recoverable. | Attach receipts, stored record IDs, notifications, and redacted logs. | |
SEC-01Blocking | Environment scope and leakage | Compare the key matrix by environment and scan client assets, build logs, and function logs for known values and patterns. | Every required value exists only in its approved scope and no secret appears in client output or logs. | Attach the key-only matrix and redacted scan result. | |
DOM-01Blocking | DNS, SSL, and hostname behavior | Resolve from multiple public resolvers and request canonical, alternate, pages.dev, and netlify.app hostnames over HTTPS. | The custom domain serves Pages with a valid certificate; alternate and platform hostnames follow the approved policy. | Attach DNS answers, certificate details, HTTP results, and Pages domain status. | |
ACC-01Blocking | Preview and application authorization | Test anonymous, approved preview, denied preview, authenticated user, expired session, and forbidden-role cases where applicable. | Preview protection and application authorization match separate documented policies. | Attach result captures without tokens. | |
OPS-01Blocking | Deploy, monitoring, and callback paths | Trigger one safe preview deploy and one production-safe operational event; inspect alerts, logs, analytics, webhooks, and status checks. | The correct environment deploys, every intended observer receives one event, and no obsolete Netlify hook mutates production. | Attach deployment, event, callback, and monitoring IDs. | |
RLB-01Blocking | Netlify restore readiness | Confirm the known-good deploy, domain association, environment, platform features, credentials, and timed routing steps. | An authorized operator can restore Netlify inside the agreed window without code changes. | Attach the rollback rehearsal duration and readiness checklist. |
Remove the scaffolding safely.
Safe after: Seven stable production days, a signed report, no unreconciled writes or submissions, and explicit closure of the Netlify rollback window.
- Export final Netlify deploy, build, form, function, analytics, audit, add-on, DNS, environment-key, and billing records required for retention.
- Archive the known-good deploy manifest, repository commit, configuration, URL/header baseline, and rollback evidence with checksums.
- Disable obsolete Netlify deploy hooks, webhooks, build notifications, identity flows, forms, functions, plugins, and add-ons one category at a time.
- Rotate secrets that existed on both platforms and revoke migration-only users, tokens, deploy keys, and temporary access policies.
- Redirect the used netlify.app hostname deliberately if required; otherwise document its retirement and monitoring.
- Remove the Netlify custom domain only after confirming Cloudflare ownership and rollback-window closure.
- Cancel Netlify paid services last, after a second person confirms archives, submission retention, billing, and recovery instructions.
- Update architecture, incident, deployment, secret, domain, form, function, access, monitoring, ownership, and next-review documentation.
When the plan met reality.
First-hand accounts are preferred. Vendor case studies are labeled, and every note below is an editorial paraphrase—follow the link for the full context.
Aki Ariga moved a Hugo blog from Netlify to Cloudflare Pages to improve access speed from Japan. Repository connection and DNS were straightforward, but the build required an explicit Hugo version and Cloudflare’s CF_PAGES_URL environment variable in place of Netlify’s URL variable. PageSpeed and perceived loading improved, although the author found that font delivery and caching—not hosting alone—accounted for much of the gain.
- Compare build-time environment variables and pin the static-site-generator version before expecting the same repository to build unchanged.
- Measure fonts and other third-party assets separately so performance gains are attributed to the correct part of the migration.
- The Git-connected static deployment moved easily, while small platform-specific build variables were the main compatibility work.
- Cloudflare DNS simplified the domain switch, but the biggest speed improvement came from correcting font caching.
Tomas Pustelnik tested Cloudflare Pages for a site previously hosted on Netlify and found that connecting the repository was only the beginning. Netlify build plugins, production-only code injection, custom headers, redirects, and the custom domain all needed separate replacements. The migration produced a meaningful performance improvement, but a one-to-one move was impossible because the site depended on more of Netlify’s surrounding ecosystem than its build output.
- Audit build plugins, injected snippets, headers, redirects, forms, functions, and domain services before moving the deployment target.
- Create destination-native replacements and verify them on a preview domain before changing production DNS.
- A repository that deploys successfully may still be functionally incomplete when platform-specific edge and build features are missing.
- The performance improvement was real for this site, but realizing it required replacing several conveniences Netlify had provided.
Verify against the primary material.
Platform behavior changes. Check these sources and the review dates above before executing a production migration.
- Cloudflare: Migrating from Netlify to PagesAccessed 2026-07-18
- Cloudflare Pages redirectsAccessed 2026-07-18
- Cloudflare Pages headersAccessed 2026-07-18
- Cloudflare Pages custom domainsAccessed 2026-07-18
- Cloudflare Pages limitsAccessed 2026-07-18
- Netlify environment variablesAccessed 2026-07-18
- Netlify file-based configurationAccessed 2026-07-18