continuous learning company
Voltar para publicações
Necy Vieira
Necy Vieira

De Vue.js + Vite para Next.js + React + TypeScript: o que uma migração de verdade te ensina

Trocar tecnologia é fácil de falar — o desafio real é reconstruir uma aplicação inteira sem perder nada pelo caminho

10/08/2026 Desenvolvimento
Migração de Vue.js para Next.js, React e TypeScript

Recentemente participei da migração de um projeto que saiu de Vue.js + Vite para uma nova stack baseada em Next.js, React e TypeScript.

E se tem uma coisa que essa experiência deixou clara é: trocar tecnologia é fácil de falar, difícil de fazer bem.

Mais do que substituir uma ferramenta por outra, o desafio real foi adaptar toda a estrutura do frontend para uma nova arquitetura — mantendo as funcionalidades existentes e sem quebrar a integração com o backend em FastAPI.

Neste artigo, compartilho os principais pontos de atenção dessa migração: o que muda de fato entre os frameworks, onde mora a maior parte da dor, e por que esse tipo de trabalho ensina muito mais sobre arquitetura de software do que sobre sintaxe nova.

Antes:  Vue.js + Vite        → FastAPI
Depois: Next.js + React + TS → FastAPI

O backend permaneceu praticamente intacto. Toda a transformação aconteceu no frontend — e é sobre isso que vamos falar.

1. Vue.js → React: não é sintaxe, é filosofia

A primeira armadilha de qualquer migração desse tipo é achar que basta "aprender a nova sintaxe".

Vue e React resolvem o mesmo problema — construir interfaces reativas — mas partem de filosofias opostas.

Vue trabalha com Single File Components (.vue), onde <template>, <script> e <style> convivem no mesmo arquivo.

A reatividade é automática: você declara um ref ou reactive, e o Vue rastreia sozinho quando e onde aquele dado é usado. As diretivas (v-if, v-for, v-model) tornam o template declarativo e compacto.

<template>
  <input v-model="nome" />
  <ul>
    <li v-for="produto in produtos" :key="produto.id">
      {{ produto.nome }}
    </li>
  </ul>
</template>

React não tem essa mágica embutida.

É JavaScript (ou TypeScript) puro com JSX, e a reatividade é explícita: você decide, via hooks, quando um estado muda e quando um componente deve re-renderizar.

const [nome, setNome] = useState("");

<input value={nome} onChange={(e) => setNome(e.target.value)} />
<ul>
  {produtos.map((produto) => (
    <li key={produto.id}>{produto.nome}</li>
  ))}
</ul>

Não existe v-model pronto — o two-way binding vira value + onChange escritos à mão.

Não existe v-if/v-for — viram expressões JavaScript comuns (&&, .map()).

Esse foi, sem dúvida, o maior choque de mentalidade da migração: sair de um modelo onde o framework cuida da reatividade para um modelo onde você é responsável por cada re-render.

2. Vite → Next.js: a pegadinha de achar que é só bundler

Aqui mora um erro comum de quem encara essa migração como "trocar a ferramenta de build".

Vite é uma build tool. Next.js é um framework completo, com decisões de arquitetura embutidas.

Com Vite + Vue Router, a aplicação era uma SPA client-side clássica: tudo renderiza no navegador, o HTML inicial é praticamente vazio, e o JavaScript assume o controle assim que carrega.

Com Next.js e o App Router, o cenário muda completamente porque Server Components são o padrão.

Isso significa que parte da aplicação pode rodar no servidor e nunca enviar JavaScript para o cliente — inclusive o fetch de dados pode acontecer direto no componente server, sem precisar da combinação clássica useEffect + axios que era natural no mundo Vue/Vite.

Foi exatamente aqui que surgiram boa parte dos erros de build durante a migração.

Qualquer componente que use useState, useEffect ou algum evento de clique precisa da diretiva "use client" no topo do arquivo — sem ela, o Next tenta renderizar aquele componente no servidor e o build simplesmente quebra.

"use client";

import { useState } from "react";

export default function Filtro() {
  const [termo, setTermo] = useState("");
  // ...
}

Entender essa fronteira entre server e client component foi, na prática, o ajuste mental mais importante de toda a migração.

3. Rotas: de Vue Router para o App Router

No mundo Vue, as rotas costumam viver em um único arquivo de configuração, mapeando path para component de forma explícita e centralizada.

No Next.js com App Router, o roteamento é baseado em estrutura de pastas dentro de app/.

Cada pasta representa uma rota; page.tsx define o conteúdo daquela rota; layout.tsx define layouts compartilhados entre rotas; e arquivos especiais como loading.tsx e error.tsx tratam automaticamente estados de carregamento e erro, sem código adicional.

app/
├── produtos/
│   ├── page.tsx          → /produtos
│   ├── [id]/
│   │   └── page.tsx      → /produtos/:id
│   └── layout.tsx

Rotas simples são tranquilas de mapear.

A dor aparece nas rotas dinâmicas e aninhadas: um /produtos/:id do Vue Router vira uma pasta [id]/page.tsx, e reorganizar rotas mais profundas exige repensar a estrutura de pastas do zero — não é um find-and-replace, é redesenho de árvore de navegação.

4. Camada de API e a tipagem "de verdade" com TypeScript

Essa foi provavelmente a etapa mais burocrática — e também a mais valiosa.

Em projetos Vue com JavaScript (ou TypeScript mais permissivo), é comum que as respostas da API circulem com tipagem implícita ou nem tipadas.

Migrando para uma stack Next.js + TypeScript com strict: true, isso deixa de ser opcional:

Definir interfaces/types para cada retorno do FastAPI
Tipar os hooks de fetch de forma explícita
Lidar com o compilador reclamando de undefined/null

O FastAPI já gera automaticamente schemas Pydantic, que podem alimentar geração de tipos no frontend — ferramentas como openapi-typescript ajudam bastante nesse processo.

interface Produto {
  id: number;
  nome: string;
  preco: number;
}

async function getProdutos(): Promise<Produto[]> {
  const res = await fetch(`${API_URL}/produtos`);
  return res.json();
}

O ganho aqui não é estético. É contrato: o frontend passa a "conversar" com o backend com garantias em tempo de compilação, não só em tempo de execução.

O que essa migração realmente ensina

O ponto mais importante de tudo isso não é técnico — é conceitual:

A stack muda, mas o domínio da aplicação não

O trabalho real de uma migração como essa não é "aprender React" ou "aprender Next.js".

É entender profundamente o que cada tela fazia, quais dados ela consumia do backend, quais regras de negócio estavam implícitas no comportamento antigo — e reconstruir tudo isso com outras ferramentas, sem quebrar o contrato com o backend em FastAPI.

Resolver os erros de build, entender a fronteira entre server e client components, reorganizar rotas, tipar corretamente as respostas da API — nada disso é sobre decorar sintaxe nova.

É sobre entender como a aplicação funciona como um todo, e ter disciplina para reconstruir essa lógica em cima de uma arquitetura diferente sem perder nada pelo caminho.

Essa é, no fim das contas, a diferença entre quem só troca de ferramenta e quem entende arquitetura de sistema.

Cada migração traz seus próprios desafios.

E, junto com eles, muito aprendizado.