メインコンテンツへスキップ

Prisma ORMをTanStack Startで使用する方法

10分

はじめに

Prisma ORMはデータベースとのやり取りを簡素化し、TanStack StartはモダンなReactアプリケーションを構築するための堅牢なフレームワークを提供します。Prisma Postgresと組み合わせることで、型安全なクエリと効率的なデータ管理により、シームレスなフルスタック開発体験を提供します。

このガイドでは、Prisma ORMとPrisma PostgresデータベースをTanStack Startプロジェクトにゼロから統合する手順を説明します。

前提条件

1. プロジェクトのセットアップ

まず、新しいTanStack Startプロジェクトを作成します。

このガイドでは、TanStack Startのドキュメントで提供されているものと同じセットアップ手順を使用します。

プロジェクトを作成したいディレクトリで、以下のコマンドを実行します。

mkdir tanstack-start-prisma
cd tanstack-start-prisma
npm init -y

これにより、tanstack-start-prismaという新しいフォルダが作成され、その中へ移動し、新しいNode.jsプロジェクトが初期化されます。

IDEでディレクトリを開き、以下の設定でtsconfig.jsonファイルを作成します。

tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ES2022",
"skipLibCheck": true,
"strictNullChecks": true
}
}

また、.gitignoreファイルも必要なので、今すぐ設定しましょう。

.gitignore
node_modules
.env
app/generated

次に、TanStack Startが現在必要とするTanStack RouterとVinxiをインストールします。

npm install @tanstack/react-start @tanstack/react-router vinxi

React、Vite Reactプラグイン、およびTypeScriptも必要です。

npm install react react-dom
npm install --save-dev @vitejs/plugin-react vite-tsconfig-paths
npm install --save-dev typescript @types/react @types/react-dom

package.jsonを更新してVinxiのCLIを使用するようにします。"type": "module"を追加し、スクリプトをVinxiのCLIを使用するように変更します。

package.json
{
"name": "tanstack-start-prisma",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"@tanstack/react-router": "^1.119.0",
"@tanstack/react-start": "^1.119.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"vinxi": "^0.5.6"
},
"devDependencies": {
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.3",
"@vitejs/plugin-react": "^4.4.1",
"typescript": "^5.8.3",
"vite-tsconfig-paths": "^5.1.4"
}
}

次に、TanStack Startのapp.config.tsファイルを作成・設定します。

app.config.ts
import { defineConfig } from '@tanstack/react-start/config'
import tsConfigPaths from 'vite-tsconfig-paths'

export default defineConfig({
vite: {
plugins: [
tsConfigPaths({
projects: ['./tsconfig.json'],
}),
],
},
})

TanStack Startが機能するためには、~/app/に5つのファイルが必要です。

  • router.tsx (ルーター設定)
  • ssr.tsx (サーバーのエントリポイント)
  • client.tsx (クライアントのエントリポイント)
  • routes/__root.tsx (アプリケーションのルート)
  • routes/index.tsx (ホームページ)

これらのコマンドで作成できます。

mkdir app
touch app/router.tsx
touch app/ssr.tsx
touch app/client.tsx
mkdir app/routes
touch app/routes/__root.tsx
touch app/routes/index.tsx

router.tsxは、ルート定義と設定でアプリケーションのメインルーターを構成します。

app/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'

export function createRouter() {
const router = createTanStackRouter({
routeTree,
scrollRestoration: true,
})

return router
}

declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}

routeTree.gen.tsが存在しないというエラーが表示されているはずです。これは予期された動作です。TanStack Startを初めて実行するときに生成されます。

ssr.tsxは、ユーザーが特定のルートにアクセスしたときに、どのルートとローダーを実行する必要があるかを知ることができます。

app/ssr.tsx
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/react-start/server'
import { getRouterManifest } from '@tanstack/react-start/router-manifest'

import { createRouter } from './router'

export default createStartHandler({
createRouter,
getRouterManifest,
})(defaultStreamHandler)

client.tsxは、ブラウザでルートを処理するためのクライアントサイドロジックを初期化します。

app/client.tsx
import { hydrateRoot } from "react-dom/client";
import { StartClient } from "@tanstack/react-start/client";
import { createRouter } from "./router";

const router = createRouter();

hydrateRoot(document, <StartClient router={router} />);

routes/__root.tsxは、アプリケーション全体のルートルートとグローバルHTMLレイアウトを定義します。

app/routes/__root.tsx
import type { ReactNode } from "react";
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from "@tanstack/react-router";

export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: "utf-8",
},
{
name: "viewport",
content: "width=device-width, initial-scale=1",
},
{
title: "Prisma TanStack Start Demo",
},
],
}),
component: RootComponent,
});

function RootComponent() {
return (
<RootDocument>
<Outlet />
</RootDocument>
);
}

function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
return (
<html>
<head>
<HeadContent />
</head>
<body>
{children}
<Scripts />
</body>
</html>
);
}

routes/index.tsxはアプリケーションのホームページです。

app/routes/index.tsx
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
component: Home,
});

function Home() {
return (
<div>
<h1>Posts</h1>
</div>
);
}

次に、実行します。

npm run dev

これにより、routeTree.gen.tsファイルが生成され、ルーティングエラーが解決されます。

ファイルツリーは次のようになります (node_modulesなし)。

.
├── app
│ ├── client.tsx
│ ├── routeTree.gen.ts
│ ├── router.tsx
│ ├── routes
│ │ ├── __root.tsx
│ │ └── index.tsx
│ └── ssr.tsx
├── app.config.ts
├── package-lock.json
├── package.json
└── tsconfig.json

2. Prismaのインストールと設定

2.1. 依存関係のインストール

Prismaを始めるには、いくつかの依存関係をインストールする必要があります。

npm install prisma tsx --save-dev
npm install @prisma/extension-accelerate @prisma/client

インストール後、プロジェクトでPrismaを初期化します。

npx prisma init --db --output ../app/generated/prisma
情報

Prisma Postgresデータベースを設定する際に、いくつかの質問に答える必要があります。お住まいの地域に最も近いリージョンと、「My __________ Project」のような覚えやすいデータベース名を選択してください。

これにより、以下が作成されます。

  • schema.prismaファイルを含むprismaディレクトリ。
  • Prisma Postgresデータベース。
  • プロジェクトルートにDATABASE_URLを含む.envファイル。
  • 生成されたPrisma Clientのoutputディレクトリ (app/generated/prisma)。

2.2. Prismaスキーマの定義

schema.prismaで、投稿用のモデルを作成し、ジェネレータをprisma-clientプロバイダを使用するように変更します。

prisma/schema.prisma
generator client {
provider = "prisma-client"
output = "../app/generated/prisma"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
}

これにより、UserPostの2つのモデルが作成され、これらは一対多の関係にあります。

2.3. Prisma Clientジェネレータの設定

次に、以下のコマンドを実行してデータベーステーブルを作成し、Prisma Clientを生成します。

npx prisma migrate dev --name init

2.4. データベースへのシード

サンプルユーザーと投稿でデータベースを埋めるために、シードデータを追加しましょう。

prisma/ディレクトリ内にseed.tsという新しいファイルを作成します。

prisma/seed.ts
import { PrismaClient, Prisma } from "../src/generated/prisma/client.js";

const prisma = new PrismaClient();

const userData: Prisma.UserCreateInput[] = [
{
name: "Alice",
email: "alice@prisma.io",
posts: {
create: [
{
title: "Join the Prisma Discord",
content: "https://pris.ly/discord",
published: true,
},
{
title: "Prisma on YouTube",
content: "https://pris.ly/youtube",
},
],
},
},
{
name: "Bob",
email: "bob@prisma.io",
posts: {
create: [
{
title: "Follow Prisma on Twitter",
content: "https://www.twitter.com/prisma",
published: true,
},
],
},
},
];

export async function main() {
for (const u of userData) {
await prisma.user.create({ data: u });
}
}

main();

次に、package.jsonを更新して、Prismaにこのスクリプトの実行方法を伝えます。

package.json
"prisma": {
"seed": "tsx prisma/seed.ts"
}

シードスクリプトを実行します。

npx prisma db seed

そして、Prisma Studioを開いてデータを確認します。

npx prisma studio

3. PrismaをTanStack Startに統合する

3.1 Prisma Clientを作成する

各ファイルで新しいPrisma Clientインスタンスを作成する代わりに、共有ファイルで単一のインスタンスを作成し、グローバルに使用します。

/libディレクトリと、その中にprisma.tsファイルを作成します。このファイルは、Prisma Clientインスタンスを作成およびエクスポートするために使用されます。

Prismaクライアントをこのようにセットアップします。

src/lib/prisma.ts
import { PrismaClient } from "../generated/prisma/client.js";
import { withAccelerate } from "@prisma/extension-accelerate";

const prisma = new PrismaClient().$extends(withAccelerate());

export default prisma;
警告

データベース接続を効率的に管理するために、接続プーラー(Prisma Accelerateなど)を使用することを推奨します。

接続プーラーを使用しない場合は、寿命の長い環境でPrismaClientをグローバルにインスタンス化することは避けてください。代わりに、リクエストごとにクライアントを作成および破棄して、データベース接続を使い果たさないようにしてください。

3.2 読み込み時にユーザーと投稿を取得する

まず、必要なモジュールをインポートします。次に、createServerFn関数を使用してサーバー関数を作成します。この関数は、.findMany()メソッドを使用してデータベースからユーザーを取得します。関連する投稿を取得するにはincludeオプションを使用します。

app/routes/index.tsx
import { prisma } from "../lib/prisma";
import { createServerFn } from "@tanstack/react-start";
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
component: Home,
});

const getUsers = createServerFn({ method: "GET" }).handler(async () => {
return prisma.user.findMany({
include: {
posts: true,
},
});
});

function Home() {
return (
<div>
<h1>Posts</h1>
</div>
);
}

TanStack Startでは、createFileRoute関数内のローダー関数を使って、読み込み時に関数を実行できます。このコードでユーザーとその投稿を読み込み時に取得します。

app/routes/index.tsx
import { prisma } from "../lib/prisma";
import { createServerFn } from "@tanstack/react-start";
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
component: Home,
loader: () => {
return getUsers();
},
});

const getUsers = createServerFn({ method: "GET" }).handler(async () => {
return prisma.user.findMany({
include: {
posts: true,
},
});
});

function Home() {
return (
<div>
<h1>Posts</h1>
</div>
);
}

Route.useLoaderData()を使用して、ローダーからの応答をメインコンポーネントに保存します。

app/routes/index.tsx
import { prisma } from "../lib/prisma";
import { createServerFn } from "@tanstack/react-start";
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
component: Home,
loader: () => {
return getUsers();
},
});

const getUsers = createServerFn({ method: "GET" }).handler(async () => {
return prisma.user.findMany({
include: {
posts: true,
},
});
});

function Home() {
const users = Route.useLoaderData();

return (
<div>
<h1>Posts</h1>
</div>
);
}

3.3 ユーザーと投稿を表示する

次に、ホームページを更新して、データベースから取得したユーザーと投稿を表示します。

usersをマッピングし、それらをpostsとともにリストで表示します。

app/routes/index.tsx
import { createFileRoute } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start";
import prisma from "../../lib/prisma";

export const Route = createFileRoute("/")({
component: Home,
loader: () => {
return getUsers();
},
});

const getUsers = createServerFn({ method: "GET" }).handler(async () => {
return prisma.user.findMany({
include: {
posts: true,
},
});
});

function Home() {
const users = Route.useLoaderData();

return (
<div>
<h1>Posts</h1>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name}
<ul>
{user.posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
}

この設定により、データベースから直接取得された投稿がページに表示されます。

次のステップ

Prisma ORMをTanStack Startと正常に統合し、シームレスなフルスタックアプリケーションを作成しました。次にできることのいくつか提案を以下に示します。

  • より複雑なデータ関係を処理するためにPrismaモデルを拡張する。
  • アプリケーションの機能を強化するために、追加のCRUD操作を実装する。
  • PrismaとTanStack Startのさらなる機能を探索して、理解を深める。
  • Prisma Postgresをチェックして、アプリケーションをスケーリングする方法を確認してください。

詳細情報


Prismaとつながる

以下を通じてPrismaの旅を続けましょう 私たちの活発なコミュニティ。情報を入手し、参加し、他の開発者と協力しましょう。

  • Xでフォローする お知らせ、ライブイベント、役立つヒントのために。
  • Discordに参加する 質問をしたり、コミュニティと話したり、会話を通じて積極的なサポートを受けたりできます。
  • YouTubeを購読する チュートリアル、デモ、ストリームのために。
  • GitHubで交流する リポジトリにスターを付けたり、問題を報告したり、問題に貢献したりしてください。
皆様のご参加を心より歓迎し、コミュニティの一員となることを楽しみにしています!

© . All rights reserved.