On this page10 sections
When Deframer converts a published Framer site, you get a standard Next.js 16 App Router project with React 19 and TypeScript, where every file is .ts or .tsx. Routes live in src/app, page content in src/views, design components with CSS modules in src/components, color and text styles in src/styles, CMS collections as JSON in src/cms, and a small runtime kit in src/lib/deframer. A README maps every URL to its route file and tells you where to edit what.
The folder tree
Here's the layout, with what each folder holds. Your site's README lists the same tree with counts for your project.
src/
app/ routes only: one page.tsx per URL (+ metadata), root layout, not-found.tsx
proxy.ts the site's URL policy (trailing slashes, 308 redirects, 404s, locale routing)
views/ page components: home.tsx + home.module.css
layouts/ layout templates (navigation, footer)
components/ design components, in the designer's folders, each with a CSS module
icons/ vectors
styles/ tokens.ts, text/ (shared text styles), fonts/ (@font-face per family)
cms/ collections: blog.ts (schema, queries) + blog.json (records)
locales/ translations (multi-locale sites)
code/ the site's own code components and overrides
vendor/ code from outside the project: marketplace components, shared modules
site/ routes.ts (routes, locales, page transitions), forms.ts
lib/forms.ts form submissions: rate limit, honeypot, validation, delivery
lib/deframer/ the runtime kit, imported as @/deframer
public/ robots.txt, sitemap.xml (+ local assets when included)Some folders appear only when your site needs them: locales/ for multi-locale sites, code/ when the site has its own code components, cms/ when it has collections. Every file and folder name is kebab-case, and imports use the @/ alias for src/, for example @/components/header/logo.
Routes: src/app
src/app holds routing and nothing else. Each URL gets one page.tsx, and each page sets its own metadata: title, description, Open Graph, Twitter card and canonical URL, evaluated at conversion time. A typical route file is short:
import type { Metadata } from "next";
import Template from "@/layouts/template";
import HomePage from "@/views/home";
export const metadata: Metadata = {
openGraph: { type: "website", title: "…", description: "…", url: "/" },
twitter: { card: "summary_large_image", title: "…", description: "…" },
alternates: { canonical: "/" },
};
export default function Page() {
return (
<Template>
<HomePage />
</Template>
);
}CMS detail pages, such as src/app/blog/[slug]/page.tsx, use generateStaticParams() to list every item, set dynamicParams = false so unknown slugs answer with the 404 page, and read each item's title, description and social image from a metadata.json beside the route.
The root layout (src/app/layout.tsx) sets site-wide metadata, including metadataBase, which points at the site's published URL. Change it when you move to a new domain. Its first line is a comment crediting Deframer; nothing about Deframer appears on the site itself.
src/proxy.ts is Next.js 16's replacement for middleware. It gives each page the URL form the site publishes (with or without a trailing slash), redirects the other form with a 308, and lets unknown URLs fall through to the 404 page.
Views and layouts
src/views holds one component per page, such as home.tsx with home.module.css. This is where you edit a page's content and layout. src/layouts holds the templates that wrap pages, usually the navigation and footer, so a change there applies everywhere.
Components and CSS modules
Design components keep the folder structure the designer used, so a component in a "Header" folder in Framer ends up at a path like src/components/header/logo.tsx, with its own CSS module next to it.
The generated code is meant to be read:
- Props and variants keep human names, so you see
variant === "Desktop", not internal IDs. - CSS module classes are named after layers and variants.
- Framer's internal attribute names are neutralized, for example
data-framer-namebecomesdata-name. - Unused code is removed and files are formatted.
Hover and press states, variants and transitions are written with motion/react. A spring keeps its stiffness, damping and mass:
const transition1 = { damping: 60, delay: 0, mass: 1, stiffness: 400, type: "spring" } as const;More on that in keeping Framer animations in Next.js with Motion.
Styles: tokens, text styles and fonts
src/styles/tokens.ts defines the site's color styles as CSS variables named after their style names, such as --token-gray-1. Change a value there and every component using it follows.
src/styles/text/ holds shared text styles as global classes, one per style, with per-breakpoint sizes inside media queries. src/styles/fonts/ has one stylesheet per font family with @font-face rules using font-display: swap.
CMS: src/cms
Each Framer CMS collection becomes two files: <collection>.json with the records, using readable field names like title, slug and publishedDate, and <collection>.ts with a plain schema and a collection object from the kit. Rich text is stored as a readable JSON tree. The details, including how to add an item, are in Framer CMS to JSON in Next.js.
Code, vendor and the kit
src/codeholds the site's own code components and overrides, from Framer's code folders.src/vendorholds code from outside the project: marketplace components and modules the site imported from URLs. They're copied in so the project doesn't fetch code at runtime.src/lib/deframeris the kit, imported as@/deframer. It's a compact, original reimplementation of the runtime APIs the generated code uses: styles, fonts, variants, breakpoints, effects, routing, CMS, overlays and forms. It is not Framer's runtime, and the project needs nothing from Framer to run. Only the kit modules your site uses are kept, and you can change them like any other part of your project.
Code components were written in Framer's editor, which doesn't type-check them, so a project containing them keeps typescript: { ignoreBuildErrors: true } in next.config.ts. See code components and overrides in Next.js for how to tighten types over time.
Site tables and forms
src/site/routes.ts lists routes, locales and page transitions, and keeps the site's reduced-motion setting. src/site/forms.ts lists each form and its fields. Every form gets its own API route that delegates to src/lib/forms.ts:
// src/app/api/forms/contact/route.ts
import { formHandler } from "@/lib/forms";
import { forms } from "@/site/forms";
export const POST = formHandler("contact", forms.contact);When the site has forms, .env.example lists FORMS_WEBHOOK_URL and one FORMS_<NAME>_WEBHOOK_URL per form.
package.json, config and README
package.json has three scripts, dev, build and start. Dependencies are pinned to exact versions: next, react, react-dom, motion, and the site's own npm packages. Dev dependencies are typescript, @types/react and @types/node.
next.config.ts sets images: { unoptimized: true }, skipTrailingSlashRedirect: true (because src/proxy.ts decides URL forms), and a redirects() list when the published site answered with redirects.
The project README.md covers how to run it, the folder tree for your site, a "Where to edit" table, a routes table, and a Forms section when there are forms. Start there. For the higher-level picture, see what you get on the home page.
FAQ
Does the project include Framer's runtime?
No. The project contains no Framer runtime. The kit in src/lib/deframer is an original reimplementation of only the APIs the generated code uses.
Who owns the converted code?
You do. Deframer claims no rights in the converted code of your site; open-source packages stay under their own licenses.
Why is `ignoreBuildErrors` on in my project?
Because your site has code components that were never type-checked in Framer. npx tsc --noEmit still reports errors, and a project without code components builds with Next's type check on.
Are assets inside the project?
Only if you turned on "Include assets locally." Otherwise images, fonts and videos load from Framer's CDN; see the FAQ for the trade-offs.
