Migrating from React to Vue 3

Overview

Moving from React to Vue 3 is a framework rewrite, not a data migration - there's no file to export and import, because the two frameworks represent components, state, and templates in fundamentally different ways. React writes components as JavaScript functions returning JSX; Vue 3 writes them as Single File Components with a <script setup> block, a <template> block, and Vue's own reactivity primitives (ref(), reactive(), computed()). Some pieces of the surrounding stack (build tooling, routing, testing) have a clean named equivalent on the other side, but the component code itself has no automated converter - porting is manual, component by component, optionally staged through an interop layer while the rewrite is in progress.

This guide covers moving from React to Vue — see each platform's release history and version notes on its technology page.

Want a plan tailored to your React → Vue 3 migration?

Get my plan

What transfers cleanly from React to Vue 3

  • Props and events follow the same shape on both sides even though the syntax differs: React passes data via JSX attributes read as function parameters, with a child calling a callback prop to communicate up; Vue declares incoming props with defineProps() (passed as :prop="value" attributes) and a child communicates up by calling defineEmits()-declared events, heard via @event-name="handler" on the parent. The concept - props down, callback/emit up - carries across directly.
  • React's children prop and Vue's <slot> are the same mechanism for parent-supplied child content, so any component built around composing children maps onto Vue's slot system without a conceptual rewrite.
  • Routing has a direct role-equivalent on each side: React Router (a separate, community/open-governance project React's own docs recommend for new projects) and Vue Router (the official router, maintained by the Vue core team) both provide route matching, nested/dynamic routes, and multiple history modes, so the routing structure of an app - not its code - carries across.
  • Build tooling converges on Vite for both ecosystems - React's own docs list Vite among the supported build-tool options, and Vue 3's official scaffolding (npm create vue@latest) is Vite-based with what Vue's docs call "first-class Vue SFC support" - so dev-server, plugin, and env-var configuration transfers more easily than component code does.
  • Global state management has a like-for-like named target: Redux Toolkit is React's official, recommended toolkit for Redux-based state, and Pinia is Vue's officially recommended state library, maintained by the Vue core team - both occupy the same "official global-state solution" role even though the APIs are different.

What does not transfer

  • JSX and Vue's template syntax are not mechanically interchangeable. JSX is JavaScript with markup - arbitrary expressions, {} interpolation, every element ultimately a function call - while Vue's <template> is HTML-based with its own directive syntax (v-if, v-for, @click, :attr) compiled ahead of time. Porting a component means rewriting its render logic in the target syntax, not a find-and-replace.
  • There is no official or widely-adopted automated React-to-Vue (or Vue-to-React) codemod. React's own react-codemod collection only transforms within React itself - class-to-hooks patterns, PropTypes extraction, lifecycle renames - and does not convert to any other framework. Migration is manual, component by component.
  • React's Hooks-based state model (useState, called only at the top of a component, never inside conditions or loops) and Vue's reactivity primitives (ref(), reactive(), computed()) are different systems, not a drop-in swap - each component's state logic has to be rewritten in the target model rather than translated.
  • Module Federation is documented as a generic, framework-agnostic way to compose separately-built bundles, but webpack's own concept page gives no explicit React-plus-Vue mixing example - treat it as generically possible for staging this migration, not as a documented, off-the-shelf pattern for this specific pair.

Effort drivers

  • Whether the app relies on Redux Toolkit for global state - that state model has to be rebuilt on Vue's reactive()/ref() pattern or Pinia, since there's no automated conversion between the two.
  • How much of the component tree leans on JSX-specific patterns (arbitrary expressions, inline function calls) rather than straightforward markup - the more JSX-heavy a component, the more manual work rewriting it into Vue's template syntax.
  • Whether the app can be staged through an interop layer at all: veaury (bidirectional React/Vue-3 interop) requires the converted components to be client-rendered, with no documented SSR support, so an SSR React app narrows which staging approach is viable.
  • How much of the app's build tooling already sits on Vite versus an older setup like Create React App (now deprecated for new apps, though still runnable in maintenance mode) - since both ecosystems converge on Vite, an app already off CRA has less build-tooling work ahead of it.

Recommended approach

Since there's no automated converter for this pair, plan the migration as a staged rewrite rather than a tool-driven one. Two documented ways to run both frameworks side by side while you work: veaury, a bidirectional React/Vue-3 interop library that lets you mount Vue 3 components inside React (or the reverse) and swap components over time - usable only for client-rendered components, since it has no documented SSR support; or single-spa, a micro-frontend framework that explicitly supports mixing React and Vue on the same page without a refresh, letting you mount a new Vue 3 app alongside the existing React app and migrate route by route or feature by feature.

Whichever staging approach you use (or if you skip staging entirely), the component rewrite itself is manual: convert each component's JSX render logic into Vue's template syntax, translate React Hooks into ref()/reactive()/computed(), and move global state from Redux Toolkit onto Pinia (or a shared reactive() object for simpler needs).

Reuse what does carry across directly - swap React Router for Vue Router while keeping the same route structure, React Testing Library for Vue Test Utils, MUI or Ant Design for Element Plus or PrimeVue, React Hook Form for VeeValidate, and Motion for Vue's built-in <Transition> component. Standardize the build setup on Vite for both sides during the transition, since that's the one place the two ecosystems already converge.

FAQ

Is there a tool that automatically converts React code to Vue 3?
No. No official or widely-adopted automated React-to-Vue codemod exists - React's own react-codemod collection only transforms within React itself (class-to-hooks patterns, PropTypes, lifecycle renames) and doesn't touch any other framework. Migration is manual, component by component, optionally staged through veaury or single-spa.
Can I run React and Vue 3 in the same app during migration?
Yes, two documented ways. veaury is a bidirectional interop library - use React components inside Vue 3, or Vue 3 components inside React - but it's Vue-3-only and its converted components need to be client-rendered, with no documented SSR support. single-spa is a micro-frontend framework that explicitly supports mixing React and Vue on the same page, letting you mount a new Vue 3 app alongside the existing React app and migrate route by route.
What's the Vue 3 equivalent of Redux for React?
Pinia. It's maintained by the Vue core team and is Vue's officially recommended state-management library for anything beyond a simple shared reactive object, occupying the same role Redux Toolkit does for React.
Do I need to rewrite my React JSX components from scratch for Vue 3?
Yes, the render logic does. JSX and Vue's template syntax aren't mechanically interchangeable - JSX is JavaScript-with-markup compiled as function calls, while Vue templates are HTML-based with their own directive syntax compiled ahead of time. There's no codemod that does this conversion for you.
What build tool should I use for a Vue 3 rewrite of a React app?
Vite, on both sides. React's own docs list Vite as a supported build-tool option, and Vue 3's official scaffolding tool is Vite-based - it's the one part of the stack where the two ecosystems already converge, which simplifies porting dev-server and plugin configuration even though it doesn't simplify porting component code.

Ready to see what this actually takes?

Get my plan

Related migrations