Turborepo/Vite/Nest.js/Prismaでプロジェクトを構築する
これは何?
React Advent Calendar 2025の1日目の記事です。
React(どころかTypeScript)経験ゼロの私がある日突然、開発案件に入り、既存の案件を参考にReactの開発環境構築を求められました。でも、既存の案件ではゼロから環境構築する手順は残っていない...どうしたらいいんだ...という過去の自分へのメモです。
環境
- Windows Pro 11
- WSL2(Windows Subsystem for Linux2)
- Docker
- Frontend:Debian 13(trixie)
- Backend:Debian 13(trixie)& PostgreSQL 18
- Visual Studio Code(以降、VSCodeと略)
FROM debian:trixie-slim
RUN apt update && apt install -y \
curl \
xz-utils \
libatomic1
WORKDIR /app
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- 5173:5173
volumes:
- .:/apps
stdin_open: true
tty: true
database:
image: postgres:18.1-trixie
container_name: my-project-postgres18
ports:
- 5432:5432
volumes:
- postgres_data:/var/lib/postgresql/18/docker
- ./init:/docker-entrypoint-initdb.d
environment:
POSTGRES_USER: hoge
POSTGRES_PASSWORD: hoge
POSTGRES_DB: my_project_db
restart: always
volumes:
postgres_data:
PostgreSQL 18でvolumesのマウントパスが変わったようなので注意。
環境構築手順
protoとNode.js/pnpmのインストール
なにはともあれNode.jsのインストールから...と過去の案件を確認したところVoltaというバージョン管理マネージャを使っていました。ただ、調べると最近はprotoがいいよ、という情報もあって、悩んだ末にprotoを採用しました。
bash <(curl -k https://moonrepo.dev/install/proto.sh | sed 's/curl --/curl -k --/g')
以下の内容が表示されたらスペースキーを押してEnterキーを押します(地味にわかりにくい)。
Which profile or config file to update?
│
│ ❯ /root/.bashrc
│ /root/.profile
│ Other
│ None
│
│ ⎵ select ⁃ ↕ cycle ⁃ ↵ submit
このままNode.jsをインストール...と思ったら、一度ターミナルを閉じて新たなターミナルを起動しないとダメでした。
あと、npmを入れようとしましたが、諸々ブラッシュアップされてそうな後発のpnpmを選びました。
protoコマンドでNode.jsとpnpmをバージョン指定(pin)してインストールします。
proto install node 25.2.1 --pin
proto install pnpm 10.24 --pin
次の内容を含んだ.prototoolsというファイルができます。
node = "25.2.1"
pnpm = "10.24.0"
このファイルをGitHubでコミットしておけば、他の開発者は
proto install
とするだけで固定されたバージョンのものがインストールされます。
Turborepoによるプロジェクト生成
既存の案件ではフロントエンドとバックエンドでプロジェクトが分かれていました。「Turborepo」というモノレポツールを使っていたので踏襲しました。並行している案件ではNxを採用していたのですが、ちょっと追い付かず...。
pnpx create-turbo@latest
ルートプロジェクトの名前をここでは「my-project」として進めます。
Packages: +92
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 92, reused 0, downloaded 92, added 92, done
? Where would you like to create your Turborepo? my-project
? Which package manager do you want to use? pnpm
>>> Creating a new Turborepo with:
Application packages
- apps/docs
- apps/web
Library packages
- packages/eslint-config
- packages/typescript-config
- packages/ui
>>> Success! Created your Turborepo at my-project
To get started:
- Change to the directory: cd my-project
- Enable Remote Caching (recommended): pnpm dlx turbo login
- Learn more: https://turborepo.com/remote-cache
- Run commands with Turborepo:
- pnpm run build: Build all apps and packages
- pnpm run dev: Develop all apps and packages
- pnpm run lint: Lint all apps and packages
- Run a command twice to hit cache
プロジェクトファイルの作成
サンプルプロジェクトで生成されるapps/webとapps/docsは削除します。
rm -rf my-project/apps/web/ my-project/apps/docs/
package.jsonにpnpmとnodeのバージョンをprotoで固定したバージョンに揃えます。
"packageManager": "pnpm@10.24.0",
"engines": {
"node": "25.2.1"
}
フロントエンドの構築
Viteによるプロジェクト作成
Turborepoで作成されたプロジェクト配下のappsに移動して、Viteのプロジェクトを作成します。
cd my-project/apps
pnpm create vite@latest
コンソールの表示にしたがってプロジェクト名や利用するフレームワークを選択します。ここではプロジェクト名を「frontend」にして書いていきます。フレームワークはReactを選択。今回、画面遷移の部分は書きませんが、プロジェクトではReact Routerを採用したので、Select a variantでReact Router v7を選んだ流れにしています。
> npx
> "create-vite"
│
◇ Project name:
│ frontend
│
◇ Select a framework:
│ React
│
◇ Select a variant:
│ React Router v7 ↗
│
◇ Use rolldown-vite (Experimental)?:
│ No
│
◇ Install with pnpm and start now?
│ Yes
> npx
> create-react-router frontend
create-react-router v7.9.6
◼ Directory:
Using frontend as project directory
◼ Using default template
See https://github.com/remix-run/react-router-templates for more
✔ Template copied
git Initialize a new git repository?
No
deps Install dependencies with pnpm?
Yes
✔ Dependencies installed
done That's it!
Enter your project directory using cd ./frontend
Check out README.md for development and deploy instructions.
Join the community at https://rmx.as/discord
Viteのプロジェクトを次のコマンドで起動して、Webブラウザから http://localhost:5173/ にアクセスします。
cd frontend
pnpx vite --host
以下の画面が表示されたらOKです。

バックエンドの構築
Nest.jsによるプロジェクト作成
こちらも既存案件の踏襲なんですがNest.jsを使ってAPI部分を作成します。プロジェクト名は「backend」にしました。
pnpx @nestjs/cli new backend
Packages: +213
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 213, reused 63, downloaded 150, added 213, done
✨ We will scaffold your app in a few seconds..
✔ Which package manager would you ❤️ to use? pnpm
CREATE backend/.prettierrc (52 bytes)
CREATE backend/README.md (5036 bytes)
CREATE backend/eslint.config.mjs (899 bytes)
CREATE backend/nest-cli.json (171 bytes)
CREATE backend/package.json (1978 bytes)
CREATE backend/tsconfig.build.json (97 bytes)
CREATE backend/tsconfig.json (677 bytes)
CREATE backend/src/app.controller.ts (274 bytes)
CREATE backend/src/app.module.ts (249 bytes)
CREATE backend/src/app.service.ts (142 bytes)
CREATE backend/src/main.ts (228 bytes)
CREATE backend/src/app.controller.spec.ts (617 bytes)
CREATE backend/test/jest-e2e.json (183 bytes)
CREATE backend/test/app.e2e-spec.ts (669 bytes)
✔ Installation in progress... ☕
🚀 Successfully created project backend
👉 Get started with the following commands:
$ cd backend
$ pnpm run start
Failed to execute command: git git init
Git repository has not been initialized
Thanks for installing Nest 🙏
Please consider donating to our open collective
to help us maintain this package.
🍷 Donate: https://opencollective.com/nest
Prisma 6では特に設定が不要でしたが、Prisma 7になってdriver adapterなるものが必要になったようなのでこちらを参考にadapter-pgを入れました。
pnpm install @prisma/adapter-pg
Prisma
ORMも既存案件の踏襲でPrismaを採用しました。個人的にはDrizzle辺りも気になる...のですが、学習時間がない(-_-;
Turborepoを利用しているので、こちらを参考にしました。
まずはpackagesフォルダ配下にdatabaseフォルダを作成して、package.jsonを置きます。
cd database
touch package.json
package.jsonの内容は次のとおりです。
{
"name": "@repo/database",
"version": "0.0.0"
}
Prismaをインストールします。今のプロジェクトではPostgreSQLを利用するのでextension-accelerateも入れました。
pnpm add prisma --save-dev
pnpm add @prisma/client
pnpm add @prisma/extension-accelerate
続けてPrismaClientをbackendのプロジェクトで参照できるように次のコマンドを実行。
pnpx prisma init --output ../../../node_modules/.prisma/client
generator clientの部分はPrisma 7になってprisma-client-jsではなくprisma-clientになるようですが、動かなかったので一旦prisma-client-jsで書きましたorz
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
output = "../../../node_modules/.prisma/client"
}
datasource db {
provider = "postgresql"
}
model users {
id Int @id @default(autoincrement())
name String
}
package.jsonにprismaのコマンドを追加します。
"scripts": {
"db:generate": "prisma generate",
"db:migrate": "prisma migrate dev",
"db:deploy": "prisma migrate deploy"
},
Turborepoでビルドできるようにturbo.jsonに以下を追加します。
"db:generate": {
"cache": false
},
"db:migrate": {
"cache": false,
"persistent": true
},
"db:deploy": {
"cache": false
}
generateとmigrateを実行。
pnpm turbo db:generate
turbo 2.6.1
• Packages in scope: @repo/database, @repo/eslint-config, @repo/typescript-config, @repo/ui, backend, frontend
• Running db:generate in 6 packages
• Remote caching disabled
┌─ @repo/database#db:generate > cache bypass, force executing e3c3b0be56aa324f
> @repo/database@0.0.0 db:generate /apps/my-project/packages/database
> prisma generate
Loaded Prisma config from prisma.config.ts.
Prisma schema loaded from prisma/schema.prisma
✔ Generated Prisma Client (v7.0.1) to ./../../node_modules/.prisma/client in
330ms
Start by importing your Prisma Client (See: https://pris.ly/d/importing-clie
nt)
Tip: Need your database queries to be 1000x faster? Accelerate offers you th
at and more: https://pris.ly/tip-2-accelerate
└─ @repo/database#db:generate ──
Tasks: 1 successful, 1 total
Cached: 0 cached, 1 total
Time: 44.158s
pnpm turbo db:migrate
turbo 2.6.1
• Packages in scope: @repo/database, @repo/eslint-config, @repo/typescript-config, @repo/ui, backend, frontend
• Running db:migrate in 6 packages
• Remote caching disabled
┌─ @repo/database#db:migrate > cache bypass, force executing d08941c40824c041
> @repo/database@0.0.0 db:migrate /apps/my-project/packages/database
> prisma migrate dev --schema=./prisma/schema.prisma
Loaded Prisma config from prisma.config.ts.
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "my_project_db", schema "public" at "da
tabase:5432"
Applying migration `20251130105035_first`
The following migration(s) have been applied:
migrations/
└─ 20251130105035_first/
└─ migration.sql
Your database is now in sync with your schema.
└─ @repo/database#db:migrate ──
Tasks: 1 successful, 1 total
Cached: 0 cached, 1 total
Time: 43.485s
PostgreSQLにusersテーブルができたことを確認して、レコードを登録します。
psql -h localhost -p 5432 -U hoge -d my_project_db
psql (18.1 (Debian 18.1-1.pgdg13+2))
Type "help" for help.
my_project_db=# \dt
List of tables
Schema | Name | Type | Owner
--------+--------------------+-------+-------
public | _prisma_migrations | table | hoge
public | users | table | hoge
(2 rows)
my_project_db=# insert into users (name) values ('佐々木舞香');
INSERT 0 1
最後に、backendでデフォルトで生成されたapp.controller.tsを書き換えました。
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { PrismaClient } from ".prisma/client"
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: "postgresql://hoge:hoge@database:5432/my_project_db"
});
const prisma = new PrismaClient({adapter});
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
if(prisma === null){
console.log("Prisma client is null");
} else {
prisma.users.findMany().then(users => {
console.log(users);
});
}
return this.appService.getHello();
}
}
https://localhost:3000にアクセスして、レコードが表示されることを確認します。
pnpm run start
> backend@0.0.1 start /apps/my-project/apps/backend
> nest start
[Nest] 83310 - 12/01/2025, 12:37:33 PM LOG [NestFactory] Starting Nest application...
[Nest] 83310 - 12/01/2025, 12:37:33 PM LOG [InstanceLoader] AppModule dependencies initialized +8ms
[Nest] 83310 - 12/01/2025, 12:37:33 PM LOG [RoutesResolver] AppController {/}: +8ms
[Nest] 83310 - 12/01/2025, 12:37:33 PM LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 83310 - 12/01/2025, 12:37:33 PM LOG [NestApplication] Nest application successfully started +1ms
[ { id: 1, name: '佐々木舞香' } ]
以上です。
Discussion