Um monorepo Turborepo permite que vários aplicativos Expo compartilhem a configuração do TypeScript, regras do ESLint e um pacote de UI, enquanto o Turbo armazena em cache tarefas de lint e typecheck entre CI. O Expo SDK 57 detecta workspaces automaticamente - você se concentra nos limites dos pacotes, não na configuração do Metro.
Cartão de receita de referência rápida - pronto para copiar e colar.
mkdir mobile-monorepo && cd mobile-monorepopnpm init# Raízes do Workspace (crie pnpm-workspace.yaml - veja Exemplo em Funcionamento)npx create-expo-app@latest apps/mobile --template default@sdk-57 --yesmkdir -p packages/ui/srcpnpm add turbo -Dw# Vincule o pacote UI ao aplicativo (de apps/mobile/package.json)# "@repo/ui": "workspace:*"pnpm installpnpm turbo run typecheckpnpm turbo run dev --filter=mobile
Quando usar isso:
Dois ou mais aplicativos Expo (consumidor + admin, versões white-label) compartilhando componentes e utilitários.
Um pacote de design system consumido pelo mobile e um futuro admin web.
CI que executa lint/typecheck em aplicativos e pacotes com cache remoto.
Colocação de módulos nativos ou lógica de negócios compartilhada sem publicar no npm.
// apps/mobile/metro.config.js - SDK 52+ default geralmente é suficienteconst { getDefaultConfig } = require("expo/metro-config");module.exports = getDefaultConfig(__dirname);
O que isso demonstra:
pnpm-workspace.yaml declara apps/* e packages/* - o Expo detecta o monorepo e configura o Metro automaticamente no SDK 57.
workspace:* cria um link simbólico para @repo/ui em apps/mobile/node_modules - o Metro agrupa o código-fonte .tsx do pacote sem uma etapa de build separada.
turbo.json executa typecheck e lint com ordenação de dependência ^ - pacotes compartilhados são verificados antes dos aplicativos.
peerDependencies em react e react-native em @repo/ui evitam cópias duplicadas do renderizador dentro do pacote.
metro.config.js mínimo - sem watchFolders manuais ao usar expo/metro-config no SDK 52+.
Workspaces permitem que apps/mobile dependa de pacotes locais via symlinks em vez de publicações no npm.
Turborepo constrói um grafo de tarefas a partir dos scripts package.json de cada workspace e armazena em cache as saídas das tarefas por hash de entrada.
Expo Metro (SDK 52+) detecta automaticamente monorepos e monitora pacotes de workspace - watchFolders / extraNodeModules manuais são necessários apenas para configurações legadas ou layouts não padrão.
Metro agrupa TSX do workspace diretamente - ao contrário do Next.js, não há um equivalente a transpilePackages; o Babel processa o código vinculado através da configuração do aplicativo.
EAS Build é executado a partir do diretório do aplicativo (apps/mobile), mas instala dependências da raiz do monorepo quando configurado com o diretório de trabalho correto.
# Execute apenas o servidor de desenvolvimento do aplicativo mobilepnpm turbo run dev --filter=mobile# Verifique o tipo do mobile e tudo o que ele dependepnpm turbo run typecheck --filter=mobile...# Verifique apenas os pacotes alterados desde o mainpnpm turbo run typecheck --filter="...[origin/main]"
Alinhe as versões no package.json raiz pnpm.overrides ou resolutions
Pacote sem react peer
Adicione peerDependencies em pacotes de workspace; instale peers no aplicativo
Módulos nativos duplicados
Habilite experiments.autolinkingModuleResolution em app.json (SDK 54+; automático no SDK 55+ monorepos)
// package.json raiz - força um único React 19 em todos os workspaces (pnpm){ "pnpm": { "overrides": { "react": "19.2.3", "react-native": "0.86.0" } }}
Pacotes de workspace precisam de seu próprio tsconfig.json com "noEmit": true para turbo run typecheck. Aliases de caminho como @/* pertencem a cada aplicativo - não à base compartilhada.
Configuração manual do Metro para monorepos no SDK 57 - Copiar receitas de watchFolders pré-SDK-52 pode conflitar com a detecção automática do Expo. Correção: Comece apenas com getDefaultConfig(__dirname); exclua substituições de resolver legadas e execute npx expo start --clear.
Versões duplicadas de react-native - Duas versões em um monorepo causam erros de build nativo e em tempo de execução. Correção:pnpm why react-native; adicione overrides na raiz; nunca permita que pacotes fixem diferentes majors de RN.
workspace:* com npm - O npm não suporta o protocolo workspace. Correção: Use pnpm (recomendação padrão do Turborepo), Yarn 4+, ou Bun; ou substitua por * e aceite garantias de vinculação mais fracas.
Telas de recursos em packages/ui - Pacote compartilhado importa expo-router e hooks de recursos; cada aplicativo herda acoplamento de navegação indesejado. Correção: Mantenha os recursos em apps/mobile/src/features/; pacotes contêm apenas primitivas.
Entradas exports ausentes - Adicionar ./card.tsx sem listá-lo em package.jsonexports quebra a resolução do Metro. Correção: Declare cada subcaminho explicitamente quando exports estiver presente.
Instalações isoladas do pnpm - O isolamento rigoroso pode quebrar algumas bibliotecas do React Native. Correção: Use nodeLinker: hoisted em pnpm-workspace.yaml se ocorrerem erros de resolução (o Expo suporta instalações isoladas a partir do SDK 54+, mas "hoisted" é mais seguro durante a configuração).
EAS Build do diretório errado - O perfil de build aponta para a raiz do repositório sem a configuração de instalação do monorepo. Correção: Defina workingDirectory do EAS para apps/mobile e instale a partir da raiz, conforme o guia de monorepos do Expo.
Workspaces sozinhos vinculam pacotes. O Turborepo adiciona um grafo de tarefas, cache local e cache remoto para que lint e typecheck pulem pacotes inalterados em CI. A filtragem (--filter=mobile) visa um aplicativo e suas dependências.
Preciso de configuração personalizada do Metro para monorepos no SDK 57?
Geralmente não. O Expo configura automaticamente o Metro quando detecta raízes de workspace e você usa expo/metro-config. Se você migrou de um guia pré-SDK-52, remova watchFolders e extraNodeModules manuais e execute npx expo start --clear.
O que significa workspace:*?
Isso diz ao pnpm para criar um link simbólico do packages/ui local para apps/mobile/node_modules em vez de baixar do npm. O * significa "qualquer versão que exista no workspace".
Pacotes compartilhados precisam de uma etapa de build?
Para agregação do Metro, não - os aplicativos importam .tsx brutos de @repo/ui. Para publicar no npm fora do monorepo, adicione uma tarefa build que emita dist/. Dentro do monorepo, as importações de origem são padrão.
Como faço para criar o aplicativo Expo dentro de apps/?
Execute pnpm install da raiz do monorepo depois para que os links do workspace sejam resolvidos.
Posso adicionar um segundo aplicativo Expo?
Sim. Crie apps/admin com o mesmo template, adicione "@repo/ui": "workspace:*", e execute pnpm turbo run dev --filter=admin. Compartilhe packages/ui e packages/typescript-config entre ambos.
Como executo apenas um aplicativo?
pnpm turbo run dev --filter=mobilepnpm turbo run typecheck --filter=mobile...
Os ... finais incluem as dependências de workspace de mobile.
Armadilha: por que o Metro falha ao resolver @repo/ui?
Causas comuns: entrada exports ausente para o subcaminho, pacote não listado em pnpm-workspace.yaml, ou pnpm install não executado a partir da raiz. Verifique se node_modules/@repo/ui é um symlink para packages/ui.
Como prevenir duplicatas de react-native?
pnpm why --depth=10 react-native
Alinhe todos os workspaces para 0.86.0. Adicione pnpm.overrides na raiz se uma dependência transitiva puxar um major diferente.
Os pacotes/ui devem usar peerDependencies?
Sim. Declare react e react-native como peers para que o aplicativo forneça uma única cópia. Instale versões correspondentes nas dependencies do aplicativo, não apenas nas devDependencies do pacote.
Onde as pastas de recursos vivem em um monorepo?
Dentro de cada aplicativo: apps/mobile/src/features/. Pacotes compartilhados contêm primitivas e utilitários - não telas de recursos do produto. Veja Estrutura de Pastas para Recursos.
Como o EAS Build funciona com monorepos?
Aponte o build para o subdiretório do aplicativo e instale a partir da raiz do monorepo. O EAS detecta pnpm-lock.yaml na raiz. Defina o eas.json do aplicativo e o diretório de trabalho de acordo com a documentação de monorepos do Expo.
Quais configurações do turbo.json o expo start precisa?
"dev": { "cache": false, "persistent": true }
Servidores de desenvolvimento são de longa execução e não devem ser armazenados em cache como tarefas concluídas.
Turborepo vs Nx para React Native?
Turborepo é mais leve - cache de tarefas e filtragem com configuração mínima. Nx adiciona geradores, comandos afetados e plugins específicos de RN com mais custo de configuração. Veja Monorepo com Nx.
Quando um monorepo é a escolha errada?
Aplicativo único, equipe única, sem pacotes compartilhados. Monorepos adicionam complexidade de instalação, risco de dependências duplicadas e configuração de ferramentas. Comece com um aplicativo autônomo; extraia um monorepo quando um segundo aplicativo ou pacote compartilhado for real - não especulativo.