Migrate from shadcn
Use this guide when you already have a shadcn project and want Frontfriend to take over design-system syncing without losing the look of your existing components.
The migration reads your current shadcn components, extracts their styling, rewrites shadcn theme classes to Frontfriend tokens by default, and stores the result as Frontfriend component config.
What gets migrated
Frontfriend scans your components/ui or src/components/ui directory and migrates:
cva(...)component variants- literal
classNameslots - supported shadcn theme classes, mapped to Frontfriend token classes
- custom CSS from your app theme file, when present
- the icon library from
components.json, when supported
Skipped components are reported in the CLI output so you can review them manually.
Prerequisites
- Existing shadcn project with
components.json - Frontfriend installed
frontfriend.config.jsin the project root- Optional but recommended: an
ff-idso migrated config can be pushed to your Frontfriend design system
module.exports = {
'ff-id': 'your-frontfriend-id-here',
aliases: {
ui: '@/components/ui',
},
};
1. Install Frontfriend
For the default Tailwind CSS v4 setup:
npm install @frontfriend/tailwind@next tw-animate-css
Or with pnpm:
pnpm add @frontfriend/tailwind@next tw-animate-css
2. Run the migration
From your project root:
npx frontfriend migrate
By default this scans all components and prepares their styling for Frontfriend. If ff-id is configured, it also pushes the migrated component config to your Frontfriend design system.
3. Initialize Frontfriend
After migration, fetch your design-system tokens:
npx frontfriend init
Frontfriend intentionally blocks init in shadcn projects that have not been migrated yet, so your existing component styling is not overwritten accidentally. If you intentionally want to skip migration and use the design system styling as-is, run:
npx frontfriend init --force
4. Import the Frontfriend theme
For Tailwind CSS v4, keep these imports in your app CSS:
@import "tailwindcss";
@import "@frontfriend/tailwind/theme.css";
The generated Frontfriend theme exposes readable utilities like bg-brand-mid, text-onbrand-strong, and border-neutral-subtle.
5. Replace or add components gradually
Once migration and init are complete, install Frontfriend components into your project:
npx frontfriend download button -f react --registry v4
For legacy Tailwind CSS v3 projects, use the legacy registry:
npx frontfriend download button -f react --registry legacy
You can migrate first, then replace components incrementally instead of doing a full rewrite.
Useful migration options
Migrate one component
npx frontfriend migrate --component button
Migrate from a specific file
npx frontfriend migrate --input ./components/ui/button.tsx
Keep raw shadcn classes
By default, Frontfriend rewrites supported shadcn classes to Frontfriend token classes. To keep the original classes:
npx frontfriend migrate --keep-shadcn-classes
Only write local output
If you do not want to push the migrated config to Frontfriend cloud:
npx frontfriend migrate --no-push
Write to a custom output path
npx frontfriend migrate --output ./frontfriend-migrated-components.json
Custom CSS handling
When migration finds custom CSS in your app theme file, it lifts that CSS into Frontfriend so it can be shared and versioned with the design system.
After a successful cloud push, Frontfriend keeps a local backup next to the original CSS file:
globals.css.bak
Then it leaves only the Tailwind and Frontfriend scaffolding imports in the app CSS.
Troubleshooting
init says the shadcn project has not been migrated
Run:
npx frontfriend migrate
npx frontfriend init
Or skip migration intentionally:
npx frontfriend init --force
A component was skipped
The CLI skips components it cannot safely extract. Run a focused migration to inspect a single component:
npx frontfriend migrate --component button
If needed, keep the component as-is and migrate it manually later.
Migrated styling looks too close to shadcn
That is expected for the first migration: Frontfriend preserves your current look. After migration, update your Frontfriend design system tokens and rerun:
npx frontfriend init --force