Framer to Next.js: real conversion tests on five different websites

We converted five public Framer sites to Next.js and measured routes, builds, pixel differences and errors: what worked, what broke, what we fixed.

Published
Updated
Reading time
8 min
Deframer cover: “Five sites, real results.” Beside it, a list of Landing, Agency, Portfolio, CMS blog and Multilingual with Multilingual selected
On this page8 sections

We converted five public Framer sites (a one-page landing page, an agency site, an animated portfolio, a CMS blog and a two-language site) to Next.js with Deframer on 25 October 2026. All five converted, every published URL got a route, and four built with no changes. One failed to build until we fixed two lines; two had a page-level defect we report below. These tests used the Next.js export; Deframer also exports the same conversion to TanStack Start, Astro, React Router and Vite.

This post gives the per-site results, what worked, what didn't, and the manual fixes. The method is summarized at the end and described in full in how we test a Framer to Next.js converter. For the same metrics over 12 sites, see the Framer to Next.js benchmark.

Which sites did we test?

Five public Framer Marketplace template demo sites, one per type, chosen by a fixed rule (for example "the first template alphabetically with two or more locales"). For the animated portfolio we deliberately took the portfolio template with the most entrance-animation data, not an easy one. We describe them by category only; the list of URLs is available on request.

Site

Type

Published pages (sitemap)

CMS

Locales

Code components

1

One-page marketing landing page

1

None

1

1

2

Multi-page agency site

8 (+2 legal pages not in the sitemap)

3 collections, 17 items

1

4

3

Animated portfolio

20 (including the 404 page)

1 collection

1

1

4

CMS-driven blog

86

4 collections, 80 items

1

0

5

Multilingual site

42 (21 per locale)

5 collections, 26 items per locale

2

6

None of the five used Framer's native forms, so forms were not exercised in this run.

What were the results?

Measured with converter commit 692fe4c on an Apple M4 Pro (12 cores, 24 GB RAM), Node 24.12, Next.js 16.3.8, headless Chrome. "Mismatch" is the share of pixels in full-page screenshots that differ from both of two live captures, at 1440, 810 and 390 px.

Site

Convert time (first run)

Sitemap URLs served

next build

tsc errors

Captures

Mean / median mismatch

Captures over 1%

Console errors (not on live)

Manual fixes

1 Landing

3.2 s

1 of 1

Pass (2.9 s)

0

3

0.28% / 0.25%

0

0

None

2 Agency

18.3 s

8 of 8

Pass (3.2 s)

1

18

5.87% / 0.16%

3 (one page)

3 (one page)

Optional: one line in the kit

3 Portfolio

14.6 s

19 of 19 (+ 404)

Pass (3.3 s)

2

39

3.91% / 0.33%

11

0

None needed to build

4 CMS blog

9.8 s

83 of 86

Pass (5.4 s)

0

30

8.87% / 0.00%

3 (one page)

4 (one page)

Rename 3 slugs

5 Multilingual

7.3 s

42 of 42 after fix

Fail; pass after fix (4.0 s)

5 syntax, then 4

36 (after fix)

0.50% / 0.12%

2

0

Close two comments

How to read it:

  • Convert time is wall time for the first conversion from the public URL, including downloading the site. On a repeat conversion with the site cached, the same sites took 2.1 to 4.3 s.
  • Build time is next build with Turbopack against an already-installed node_modules; it does not include npm install.
  • tsc errors come from npx tsc --noEmit. Every project here contained code components or vendored code, so it ships with typescript.ignoreBuildErrors on and builds despite type errors (see below).
  • Mean vs median: one broken page moves the mean a lot. Site 4's mean of 8.87% comes from a single CMS page at about 88%; its other 27 captures were all under 1%.

Functional checks against next start: on all five sites an unknown URL returned 404 (as on the live site), and robots.txt and sitemap.xml were served. On the four sites where our script could compare metadata (72 pages), titles, descriptions and social images matched the live pages; differences are listed under "known limitations".

What worked?

These are measurements unless marked as our judgment.

  • Route coverage. Every URL in each live sitemap had a prerendered route. Pages the designer kept out of the sitemap (two legal pages on site 2) were converted too and stayed out of sitemap.xml.
  • CMS. Sites 2, 4 and 5 had their collections written to src/cms/*.json with every item; site 5 got one JSON file per collection per locale. Unknown item slugs returned 404 instead of an empty page.
  • Locales. Site 5's German and English URLs all answered as on the live site, including /de redirecting to /de/ with a 308, as the live host does.
  • Responsive layout. Page heights matched the live page at all three widths on every capture except the one broken CMS page and one capture where the live site itself changed height between captures.
  • Animations. With motion allowed (a second pass on the first routes of each site), 23 of 26 captures were under 1% mismatch; the other three measured 1.5%, 1.5% and 4.5%. Pixel captures show the end state of entrance animations, not their timing, so this says nothing about how the motion feels.
  • Code. Every source file was .ts or .tsx; there were no .js bundles in src. Package versions were pinned to what each live site loads (for example a smooth-scroll package at an exact version).
  • Speed. Conversion took 3 to 18 seconds; most of it was downloading the site.

What didn't work?

Each of these is in the migration problems database with its cause and fix.

  1. Site 5 didn't build. next build failed with "Parsing ecmascript source code failed" in two code components. The converter's pass that removes Framer editor annotations from comments left two documentation comments unclosed (/** @supportedLayoutWidth auto with no */). This is a converter bug.
  2. One page on site 2 threw an animation error. MotionCancelOptimisedAnimation is not a function stopped part of the page from appearing (33 to 38% mismatch at all widths). The cause is a race in the kit's entrance-animation handoff. The same error appeared on one site in the larger benchmark.
  3. Three CMS posts on site 4 returned 404. Their slugs contained a curly apostrophe (’). The live site serves them; the converted project prerenders them but doesn't match the percent-encoded request.
  4. Site 3 had intermittent differences. Eleven of 39 captures were over 1%, often on a route that measured under 1% at another width. Rechecking showed two kinds: the live site's own preloader hadn't finished when it was captured (a measurement artifact), and, on one project page, a text block and gallery images that hadn't appeared yet on the converted page at capture time. The cause of the second isn't established; the same pages measured under 1% at other widths and in other runs.
  5. Our interaction checker didn't work on this output. It finds elements by Framer's data-framer-name attribute, which the converter renames to data-name, so it reported "element not found" for most interactions. That is a gap in our test tooling, so we made no interaction claims from it.

What manual fixes were needed?

Site

Fix

Effort (our estimate)

Required to build?

5

Add */ to the end of the two unclosed comment lines in src/code/

1 minute

Yes

4

Rename the three slugs with ’ in src/cms/blog.json to ASCII, and add redirects from the old URLs in next.config.ts

10 minutes

No

2

In src/lib/deframer/effects/appear-script.ts, call MotionCancelOptimisedAnimation only if it still exists (?.()) inside the MotionCheckAppearSync listener

5 minutes

No

2, 3, 5

Fix the tsc errors in the site's own code components (for example ease: "easeInOut" as const) before turning off ignoreBuildErrors

10 to 30 minutes per site

No

After the site 5 fix, the project built in 4.0 s, all 42 sitemap URLs answered correctly, and 34 of 36 captures were under 1% mismatch.

What are the known limitations?

  • Type errors in code components. Code written in Framer's code editor is never type-checked by Framer, and three of the five projects had tsc errors in that code or in vendored code. Builds pass because next.config.ts keeps typescript.ignoreBuildErrors on, with a comment saying why. See Framer code components and overrides in Next.js.
  • One collection stayed in Framer's format. On site 3, the converter kept one collection on Framer's reader instead of plain JSON (it says so in a notice). The pages render, but you can't edit that content as JSON.
  • A robots value was missing. On site 3, <meta name="robots" content="max-image-preview:large"> was on the live pages and missing on 16 of 19 converted pages. Add it in src/app/layout.tsx metadata if you want it.
  • lang differs. Converted pages set <html lang="en"> where two live sites had no lang. We consider that an improvement, but it is a difference.
  • Assets stayed on Framer's CDN, because we tested in CDN mode (the default). A local-assets run would also test downloads; see Framer fonts and assets: CDN vs local.
  • An extra font request. Converted pages on site 3 requested a Google Fonts stylesheet for Framer's system-font placeholder, which the browser blocked. It had no visible effect.

How did we test?

In short:

  1. Picked five sites by a written rule from a public list of 150 Marketplace template demos.
  2. Converted each from its public URL (assets on the CDN), timing the run.
  3. Ran tsc --noEmit and next build, then compared each live sitemap.xml with the prerendered routes.
  4. Captured full-page screenshots of every route (up to 13 per site, including CMS item pages) at 1440, 810 and 390 px: the live page twice and the local build once, counting pixels that differ from both live captures. Then a second pass with animations allowed.
  5. Requested every sitemap URL, an unknown URL, robots.txt and sitemap.xml from next start, and compared metadata with the live pages.
  6. Read the code, then deleted each project.

All measurements were taken within about two hours, on a machine that was also running other jobs, over a home internet connection. Times are indicative. The full method, including how the pixel comparison works and its limits, is in our testing methodology. We will re-run these tests on later versions and update this post.

If you're planning your own migration, the Framer to Next.js migration checklist and what you get in a converted Next.js project are good next reads.

FAQ

How long does it take to convert a Framer site to Next.js?

In our tests the conversion itself took 3 to 18 seconds per site, most of it downloading the published site. Reviewing the result, fixing what the tests found and deploying takes far longer than the conversion.

Does a converted Framer site build without changes?

Four of our five did. The fifth needed a two-line fix to close two comments before next build succeeded.

How close does a converted site look to the original?

On four of the five sites, most captures differed from the live page by under 1% of pixels. Specific pages had defects (an animation error, three CMS posts returning 404, intermittent differences on one portfolio), which we list above.

Do Framer CMS collections survive the conversion?

On three of the four sites with collections, every collection became JSON with all its items, per locale on the multilingual site. On the fourth, one collection stayed in Framer's format but its pages still rendered.

Were the test sites cherry-picked?

The sites were chosen by a rule written before any conversion, and no site was replaced after a failure. They are template demos, which tend to be cleaner than client sites; the benchmark adds sites on custom domains.