Jak założyć monorepo w Turborepo dla React i Node krok po kroku
- Jak założyć pierwsze monorepo w Turborepo dla projektu React i Node
- Po co Ci monorepo z Turborepo w projekcie React i Node
- Dlaczego właśnie Turborepo do monorepo React + Node
- Przygotowanie środowiska przed założeniem monorepo
- Tworzenie szkieletu monorepo z Turborepo
- Dodanie aplikacji React (frontend) do monorepo
- Dodanie aplikacji Node.js (backend/API) do monorepo
- Tworzenie współdzielonych pakietów: UI i utils
- Wykorzystanie współdzielonych pakietów w aplikacjach
- Konfiguracja Turborepo w pliku turbo.json
- Skrypty w głównym package.json i wygodna praca z monorepo
- Dobre praktyki i kolejne kroki z monorepo Turborepo
Jak założyć pierwsze monorepo w Turborepo dla projektu React i Node
Czy zastanawiałeś się kiedyś, jak założyć pierwsze monorepo w Turborepo dla projektu React i Node krok po kroku bez doświadczenia w DevOps? Jeśli tak, to jesteś w dobrym miejscu. Być może czujesz, że Twój projekt zaczyna się rozrastać w niekontrolowany sposób, pojawia się kilka aplikacji, a każda ma swoje zależności i konfiguracje.
Może frustruje Cię ciągłe przełączanie się między folderami, duplikowanie kodu oraz problemy z wersjami bibliotek. To całkowicie normalne na pewnym etapie rozwoju projektu. Na szczęście istnieje eleganckie rozwiązanie, które porządkuje ten chaos – monorepo.
Gdy dodamy do tego Turborepo, otrzymujemy narzędzie, które pozwala nawet osobie bez doświadczenia w DevOps poczuć się jak świadomy architekt systemu. Monorepo upraszcza organizację kodu, a Turborepo automatyzuje i przyspiesza zadania związane z budowaniem oraz testowaniem.
W tym artykule zobaczysz, jak założyć pierwsze monorepo w Turborepo dla projektu React i Node krok po kroku bez doświadczenia w DevOps. Przejdziemy od inicjalizacji repozytorium, przez tworzenie aplikacji React i Node.js, po współdzielone pakiety oraz konfigurację Turborepo. Po lekturze będziesz mógł powiedzieć: „Tak, mam swoje pierwsze monorepo i działa!”.
Przygotuj się na praktyczną podróż, która zmieni Twoje podejście do organizacji kodu, a przy okazji pokaże, że zaawansowana konfiguracja nie musi być trudna ani skomplikowana.

Po co Ci monorepo z Turborepo w projekcie React i Node
Zanim zobaczysz, jak założyć pierwsze monorepo w Turborepo dla projektu React i Node, warto zrozumieć, dlaczego ten model zyskuje na popularności. Wyobraź sobie system, w którym masz aplikację webową w React, backend w Node.js oraz planowaną aplikację mobilną.
Do tego dochodzą wspólne komponenty UI, walidacje, typy danych i logika biznesowa. Jeśli każdy z tych elementów żyje w osobnym repozytorium, bardzo łatwo wpaść w pułapkę „dependency hell” i niekończących się aktualizacji. Monorepo pozwala spiąć to wszystko w jednym miejscu.
Kluczowe zalety monorepo
Monorepo oferuje kilka bardzo praktycznych korzyści, które szybko odczujesz w codziennej pracy:
-
Współdzielenie kodu
Możesz tworzyć biblioteki komponentów React, wspólne funkcje, typy TypeScript i używać ich w wielu aplikacjach. Koniec z kopiowaniem kodu i utrzymywaniem kilku wersji tej samej logiki. -
Spójność konfiguracji
Łatwiej utrzymać tę samą wersję ESLint, Prettiera, TypeScript oraz narzędzi testowych w całym ekosystemie. Zmiana w jednym miejscu od razu wpływa na wszystkie projekty w monorepo. -
Uproszczone zależności
Menedżer pakietów (np. pnpm) może deduplikować zależności, co oszczędza miejsce i przyspiesza instalacje. Nie instalujesz tych samych bibliotek w kilku repozytoriach osobno. -
Atomowe zmiany i refaktoryzacje
Możesz jednym commitem wprowadzać zmiany, które obejmują frontend, backend i współdzielone pakiety. Łatwiej też bezpiecznie refaktoryzować API lub kontrakty pomiędzy serwerem a klientem.
Dzięki temu monorepo staje się naturalnym wyborem, gdy Twój projekt zaczyna składać się z wielu współpracujących ze sobą części.
Dlaczego właśnie Turborepo do monorepo React + Node
Skoro wiesz już, czemu monorepo ma sens, przejdźmy do narzędzia, które znacząco ułatwia pracę – Turborepo. Jest to rozwiązanie stworzone przez Vercel, twórców Next.js, zaprojektowane specjalnie z myślą o wydajnym zarządzaniu wieloma pakietami.
Jeśli nie masz doświadczenia w DevOps, Turborepo jest dobrym wyborem, ponieważ łączy prostotę z bardzo wysoką wydajnością. Nie wymaga skomplikowanej konfiguracji, a jednocześnie pozwala na zaawansowane optymalizacje.
Co daje Turborepo w praktyce
Najważniejsze cechy Turborepo to:
-
Inkrementalne budowanie
Budowane są tylko te części monorepo, które naprawdę się zmieniły. Jeśli edytujesz mały pakiet, nie przebudujesz całego ekosystemu, co znacząco oszczędza czas. -
Inteligentne buforowanie
Turborepo zapamiętuje wyniki zadań (np. build, test) i przy ponownym uruchomieniu wykorzystuje cache, jeśli wejścia się nie zmieniły. Działa to zarówno lokalnie, jak i opcjonalnie zdalnie. -
Równoległe uruchamianie zadań
Zadania dla wielu pakietów mogą być wykonywane jednocześnie. W praktyce oznacza to większe wykorzystanie zasobów komputera i krótszy czas oczekiwania. -
Minimalna konfiguracja
Plikturbo.jsonjest prosty, a sensowny szkielet konfiguracji generuje się automatycznie. Dzięki temu możesz szybko zacząć, nie znając zaawansowanych narzędzi DevOps. -
Dobra współpraca z npm, Yarn i pnpm
Możesz używać ulubionego menedżera pakietów, chociaż w monorepo często rekomendowany jest pnpm.
W projekcie React + Node Turborepo sprawia, że frontend i backend działają jak części jednego organizmu. Możesz współdzielić typy, logikę oraz konfigurację i budować całość w sposób szybki oraz przewidywalny.
Przygotowanie środowiska przed założeniem monorepo
Zanim przejdziesz do tworzenia monorepo z Turborepo dla React i Node, upewnij się, że masz kilka podstawowych narzędzi. Nie jest to nic wyszukanego – to standardowy zestaw w świecie JavaScript/TypeScript.
Niezbędne narzędzia
-
Node.js (LTS)
Zainstaluj wersję LTS, ponieważ jest stabilna i szeroko wspierana. Po instalacji sprawdź wersję poleceniem:bash node -v -
Menedżer pakietów: npm, Yarn lub pnpm
- npm jest instalowany razem z Node.js (
npm -v) - Yarn można dodać globalnie (
npm install -g yarn) - pnpm także globalnie (
npm install -g pnpm)
W kontekście monorepo pnpm jest szczególnie polecany ze względu na oszczędność miejsca i sprytne zarządzanie zależnościami.
-
Git
System kontroli wersji jest niezbędny do pracy z kodem i historią zmian. Po instalacji sprawdzasz go:bash git --version -
Edytor kodu (np. VS Code)
Dobrze, jeśli wspiera TypeScript, linting i ma rozszerzenia przyjazne monorepo. VS Code świetnie spełnia te wymagania.
Gdy wszystko jest gotowe, możesz zająć się tym, co najważniejsze – praktycznym utworzeniem pierwszego monorepo Turborepo dla React i Node.
Tworzenie szkieletu monorepo z Turborepo
Pierwszym krokiem będzie inicjalizacja projektu przy użyciu wbudowanego kreatora Turborepo. Dzięki temu od razu otrzymasz sensowną strukturę folderów i plików konfiguracyjnych.
Krok 1: Inicjalizacja monorepo
W terminalu przejdź do katalogu, w którym chcesz utworzyć projekt, i wykonaj:
npx create-turbo@latest
Kreator zapyta, gdzie utworzyć monorepo. Podaj nazwę, na przykład:
? Where would you like to create your turborepo? my-fullstack-app
Po chwili zobaczysz informację, że Turborepo zostało utworzone oraz podpowiedź kolejnych kroków:
cd my-fullstack-app
pnpm install
pnpm dev
Przejdź do katalogu i zainstaluj zależności:
cd my-fullstack-app
pnpm install
Struktura projektu będzie wyglądała mniej więcej tak:
my-fullstack-app/
├── apps/
│ ├── docs/
│ └── web/
├── packages/
│ ├── eslint-config-custom/
│ ├── tsconfig/
│ └── ui/
├── .gitignore
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── turbo.json
Najważniejsze elementy to:
apps/– główne aplikacje (frontend, backend, dokumentacja itp.)packages/– współdzielone pakiety (np. komponenty UI, wspólne konfiguracje)pnpm-workspace.yaml– mówi pnpm, żeapps/ipackages/to workspace’yturbo.json– centralna konfiguracja zadań Turborepo
Możesz już uruchomić domyślne aplikacje:
pnpm dev
To dobry moment, by upewnić się, że startowe monorepo działa poprawnie, zanim zaczniesz je dostosowywać do swoich potrzeb.
Dodanie aplikacji React (frontend) do monorepo
Kolejnym etapem w tworzeniu pierwszego monorepo Turborepo dla React i Node jest przygotowanie aplikacji frontendowej. Możesz wykorzystać istniejące apps/web, ale dla przejrzystości zaczniemy od zera.
Krok 2: Tworzenie aplikacji React z Vite
Najpierw usuń domyślne aplikacje, jeśli chcesz mieć czystą strukturę:
rm -rf apps/web apps/docs
Następnie utwórz nową aplikację React z TypeScript przy użyciu Vite:
pnpm create vite apps/web --template react-ts
Po przejściu kreatora wejdź do folderu aplikacji i zainstaluj lokalne zależności:
cd apps/web
pnpm install
cd ../..
Sprawdź, czy w głównym package.json znajdują się skrypty Turborepo:
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test"
}
Upewnij się również, że w apps/web/package.json są podstawowe skrypty Vite:
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
}
Teraz możesz uruchomić frontend poprzez Turborepo:
pnpm dev --filter=web
Otwórz przeglądarkę na http://localhost:5173, aby zobaczyć działającą aplikację React w ramach monorepo. To pierwszy widoczny efekt integracji React z Turborepo.
Dodanie aplikacji Node.js (backend/API) do monorepo
Mając już frontend, czas dodać backend. Dzięki monorepo i Turborepo backend będzie częścią tego samego repozytorium, co ułatwi współdzielenie logiki i typów.

Krok 3: Tworzenie aplikacji Node.js z Express
Utwórz katalog na API:
mkdir apps/api
cd apps/api
Zainicjuj projekt Node.js:
pnpm init
Zainstaluj Express i TypeScript:
pnpm add express
pnpm add -D typescript @types/express @types/node
Dodaj tsconfig.json korzystający z bazowej konfiguracji:
{
"extends": "tsconfig/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"module": "CommonJS",
"target": "ES2022",
"lib": ["ESNext"],
"esModuleInterop": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": false
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
Stwórz prosty serwer Express w src/index.ts:
import express from 'express';
const app = express();
const port = process.env.PORT || 4000;
app.use(express.json());
app.get('/api', (req, res) => {
res.json({ message: 'Witaj ze świata Node.js w monorepo!' });
});
app.listen(port, () => {
console.log(`Serwer API działa na porcie ${port}`);
});
Skonfiguruj skrypty w apps/api/package.json:
{
"name": "api",
"version": "1.0.0",
"main": "dist/index.js",
"scripts": {
"dev": "ts-node-dev src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"lint": "eslint src/**/*.ts"
},
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^20.11.17",
"eslint-config-custom": "workspace:*",
"ts-node-dev": "^2.0.0",
"typescript": "^5.3.3"
}
}
Zainstaluj brakujące narzędzia:
pnpm add -D ts-node-dev
pnpm add -D eslint
cd ../..
pnpm install
Uruchom backend:
pnpm dev --filter=api
Po wejściu na http://localhost:4000/api zobaczysz odpowiedź z serwera. Teraz zarówno React, jak i Node.js żyją w jednym monorepo zarządzanym przez Turborepo.
Tworzenie współdzielonych pakietów: UI i utils
Serce dobrze zaprojektowanego monorepo to współdzielone pakiety, z których korzysta wiele aplikacji. W tym kroku przygotujesz pakiet z komponentami React (ui) oraz pakiet z funkcjami pomocniczymi (utils).
Krok 4: Pakiet ui z komponentami React
Utwórz katalog pakietu:
mkdir packages/ui
cd packages/ui
pnpm init
Skonfiguruj packages/ui/package.json:
{
"name": "ui",
"version": "0.0.0",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"sideEffects": false,
"license": "MIT",
"files": [
"dist/**"
],
"scripts": {
"build": "tsup src/index.tsx --format esm,cjs --dts --external react",
"dev": "tsup src/index.tsx --format esm,cjs --dts --external react --watch",
"lint": "eslint src/",
"clean": "rm -rf .turbo && rm -rf dist"
},
"devDependencies": {
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19",
"eslint": "^8.56.0",
"eslint-config-custom": "workspace:*",
"react": "^18.2.0",
"tsconfig": "workspace:*",
"tsup": "^8.0.1",
"typescript": "^5.3.3"
},
"publishConfig": {
"access": "public"
}
}
Zainstaluj tsup (jeśli jeszcze tego nie zrobiłeś):
pnpm add -D tsup
Dodaj tsconfig.json:
{
"extends": "tsconfig/react-library.json",
"include": ["."],
"exclude": ["node_modules", "dist"]
}
Utwórz prosty komponent Button:
// packages/ui/src/Button.tsx
import * as React from "react";
interface ButtonProps {
children: React.ReactNode;
onClick?: () => void;
}
export const Button = ({ children, onClick }: ButtonProps) => {
return (
<button
onClick={onClick}
style={{
padding: "10px 20px",
borderRadius: "5px",
border: "1px solid #ccc",
backgroundColor: "#f0f0f0",
cursor: "pointer",
margin: "5px",
}}
>
{children}
</button>
);
};
Oraz plik główny:
// packages/ui/src/index.tsx
export { Button } from "./Button";
Wróć do katalogu głównego i zainstaluj zależności:
cd ../..
pnpm install
Krok 5: Pakiet utils ze wspólnymi funkcjami
Utwórz katalog:
mkdir packages/utils
cd packages/utils
pnpm init
Skonfiguruj packages/utils/package.json:
{
"name": "utils",
"version": "0.0.0",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"sideEffects": false,
"license": "MIT",
"files": [
"dist/**"
],
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts",
"dev": "tsup src/index.ts --format esm,cjs --dts --watch",
"lint": "eslint src/",
"clean": "rm -rf .turbo && rm -rf dist"
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-custom": "workspace:*",
"tsconfig": "workspace:*",
"tsup": "^8.0.1",
"typescript": "^5.3.3"
},
"publishConfig": {
"access": "public"
}
}
Dodaj tsconfig.json:
{
"extends": "tsconfig/base.json",
"include": ["."],
"exclude": ["node_modules", "dist"]
}
Utwórz funkcję formatDate:
// packages/utils/src/formatDate.ts
export const formatDate = (date: Date): string => {
return date.toLocaleDateString('pl-PL', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
};
Oraz plik główny:
// packages/utils/src/index.ts
export { formatDate } from "./formatDate";
Na koniec wróć do głównego katalogu i odśwież zależności:
cd ../..
pnpm install
Masz już dwa współdzielone pakiety, które możesz wykorzystywać zarówno w aplikacji React, jak i Node.js, w jednym monorepo Turborepo.
Wykorzystanie współdzielonych pakietów w aplikacjach
Kiedy pakiety ui i utils są gotowe, pora zacząć z nich korzystać. To właśnie w tym momencie widać największe korzyści z monorepo Turborepo w projekcie React + Node.
Krok 6: Użycie ui i utils w aplikacji React
Otwórz apps/web/package.json i dodaj odwołania do workspace’ów:
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ui": "workspace:*",
"utils": "workspace:*"
}
W pliku apps/web/src/App.tsx zaimportuj komponent i funkcję:
import React, { useState } from 'react';
import './App.css';
import { Button } from 'ui';
import { formatDate } from 'utils';
function App() {
const [count, setCount] = useState(0);
const handleButtonClick = () => {
setCount((prevCount) => prevCount + 1);
};
return (
<>
<h1>Vite + React + Monorepo!</h1>
<div className="card">
<Button onClick={handleButtonClick}>
Licznik to {count}
</Button>
<p>
Dzisiaj jest: {formatDate(new Date())}
</p>
<p>
Edytuj <code>src/App.tsx</code> i zapisz, aby przetestować HMR.
</p>
</div>
<p className="read-the-docs">
Kliknij na logo Vite i React, aby dowiedzieć się więcej
</p>
</>
);
}
export default App;
Zainstaluj ponownie zależności, aby pnpm utworzył odpowiednie symlinki:
pnpm install
Uruchom frontend:
pnpm dev --filter=web
Teraz frontend wykorzystuje wspólny komponent Button oraz funkcję formatDate. Zmiany w pakietach ui i utils będą natychmiast widoczne w aplikacji React dzięki HMR i trybowi watch.
Krok 7: Użycie utils w backendzie Node.js
W backendzie możesz użyć tych samych funkcji pomocniczych co w React, co pozwala zachować spójność logiki w całym systemie.
W pliku apps/api/package.json dodaj:
"dependencies": {
"express": "^4.18.2",
"utils": "workspace:*"
}
Zmodyfikuj apps/api/src/index.ts, aby używać formatDate:
import express from 'express';
import { formatDate } from 'utils';
const app = express();
const port = process.env.PORT || 4000;
app.use(express.json());
app.get('/api', (req, res) => {
res.json({
message: 'Witaj ze świata Node.js w monorepo!',
currentDate: formatDate(new Date()),
});
});
app.listen(port, () => {
console.log(`Serwer API działa na porcie ${port}`);
});
Zaktualizuj zależności:
pnpm install
Uruchom backend:
pnpm dev --filter=api
Odwiedzając http://localhost:4000/api, zobaczysz wiadomość wraz z datą sformatowaną w identyczny sposób, jak w aplikacji React. To idealny przykład, jak monorepo Turborepo pozwala współdzielić logikę między frontendem a backendem.
Konfiguracja Turborepo w pliku turbo.json
Plik turbo.json jest centrum zarządzania zadaniami w monorepo. To tutaj definiujesz, jak mają działać komendy build, dev, lint oraz test dla wszystkich pakietów.
Jak działa pipeline Turborepo
Przykładowa konfiguracja turbo.json wygląda tak:
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [
"**/.env"
],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
},
"test": {
"dependsOn": ["^build"],
"outputs": []
}
}
}
Najważniejsze elementy:
build– Turborepo uruchamiabuilddla pakietu oraz dla wszystkich jego zależności (^build).dev– zadania w trybie deweloperskim nie są cache’owane i działają jako procesy długotrwałe.lintoraztest– zadania bez artefaktów, które mogą być uruchamiane dla wielu pakietów równolegle.
Przydatne przykłady użycia:
- Budowa wszystkiego:
bash pnpm build - Dev dla wszystkich aplikacji z
dev:bash pnpm dev - Lint tylko pakietu
ui:bash pnpm lint --filter=ui - Budowa
webwraz z zależnościami:bash pnpm build --filter=web^...
Dzięki temu nawet bez doświadczenia w DevOps masz pod kontrolą cały proces uruchamiania, budowania i testowania wielu pakietów jednocześnie.
Skrypty w głównym package.json i wygodna praca z monorepo
Na koniec warto dodać kilka skryptów w głównym package.json, aby łatwiej zarządzać monorepo. Dzięki temu nie musisz za każdym razem wpisywać turbo run ... ręcznie.
Krok 8: Skrypty ułatwiające codzienną pracę
Przykładowa konfiguracja głównego package.json:
{
"name": "my-fullstack-app",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test",
"clean": "turbo run clean",
"changeset": "changeset",
"release": "turbo run build --filter=docs... && changeset publish"
},
"devDependencies": {
"turbo": "latest",
"eslint-config-custom": "workspace:*",
"prettier": "latest",
"@changesets/cli": "^2.27.1"
},
"packageManager": "[email protected]"
}
Teraz możesz:
- Uruchomić wszystkie dev-serwery:
bash pnpm dev - Zbudować cały projekt:
bash pnpm build - Przelintować wszystkie pakiety:
bash pnpm lint
Monorepo z Turborepo staje się dzięki temu wygodnym środowiskiem pracy, w którym wszystkie części systemu są dostępne z jednego miejsca.
Dobre praktyki i kolejne kroki z monorepo Turborepo
Masz już działające monorepo z aplikacją React, backendem Node.js oraz współdzielonymi pakietami. To solidna baza, ale warto jeszcze spojrzeć na kilka dobrych praktyk oraz możliwych ścieżek rozwoju projektu.
Dobre praktyki w monorepo
-
Atomiczne commity
Zmiany obejmujące frontend, backend i pakiety traktuj jako jedną logiczną całość. Łatwiej wtedy śledzić historię i przywracać zmiany. -
Jasne granice pakietów
Każdy pakiet (ui,utilsitd.) powinien mieć jasno określony zakres odpowiedzialności. Unikaj cyklicznych zależności między pakietami. -
Wspólna konfiguracja
Korzystaj z centralnych konfiguracji dla ESLint, Prettier i TypeScript (np. pakietyeslint-config-custom,tsconfig). Ułatwia to utrzymanie spójności w całym kodzie. -
Testy w każdym pakiecie i aplikacji
Dzięki Turborepo testy mogą być uruchamiane równolegle. Dodawaj testy w miarę rozwoju monorepo, aby utrzymać wysoką jakość.
Co możesz zrobić dalej
Mając pierwsze monorepo Turborepo dla React i Node, możesz:
- Dodać kolejne aplikacje, np. panel admina lub aplikację mobilną.
- Rozbudować współdzielone pakiety o hooki React, walidatory, logikę biznesową.
- Zintegrować CI/CD i wykorzystać cache Turborepo na serwerach CI.
- Pogłębić znajomość
turbo.json, eksperymentując z pipeline’ami i buforowaniem.
Dzięki temu, że wszystko żyje w jednym repozytorium, zarządzasz kodem jak dobrze zorganizowaną firmą, w której wszystkie działy korzystają z tych samych narzędzi i standardów.
Monorepo z Turborepo pokazuje, że nawet bez doświadczenia w DevOps możesz zbudować nowoczesny, skalowalny ekosystem dla aplikacji React i Node – krok po kroku, w sposób przejrzysty i kontrolowany.