先日ヨドバシのクレカ明細を分析するツールを作ったときにPrismaを5系から7系に上げたのですが、
公式のマイグレーションガイドだけでは解決しない点がいくつかあったので、メモを残しておきます。
構成
今回話題に上げるアプリケーション構成は、TypeScriptを利用して、フルスタックNext.jsをyarnでモノレポ管理しているものになります。
またDBはPostgreSQLです。
/
├── apps/
│ └── web/ Next.jsアプリケーション
└── packages/
└── db/ Prisma管理ディレクトリ
Prisma v5の時点では、packages/db配下でPrismaのクライアントファイルを生成すればnode_modulesに配置されるので、web側では何もしなくてもPrismaClientをimportすることができていました。
以前はnext.config.jsにtranspilePackages: ["@sample-app/db"],のように書いていましたが、
ホスティングされているからかyarn v4で管理している状態では書かなくても利用することができていました。
https://nextjs.org/docs/app/api-reference/config/next-config-js/transpilePackages
今回、この構成はなるべく維持しつつ、v7に上げていきます。
関連しそうなパッケージとバージョンは以下の通りです。
"yarn": "4.12.0"
"next": "16.1.6"
"@prisma/adapter-pg": "7.4.0"
"@prisma/client": "7.4.0"
"dotenv": "17.3.1"
"pg": "8.18.0"
"prisma": "7.4.0"
"pglite-prisma-adapter": "0.7.2"
"tsx": "4.21.0"
"typescript": "5.9.3"
packages/db側の変更点
Prisma関連のファイルを管理するパッケージをpackages/dbに配置しているのですが、変更が必要になったファイルは以下の通りです。
変更が必要なファイル
- package.json
- schema.prisma
- seed.ts
- .gitignore <- 忘れないように注意
新規追加のファイル
package.json関連の話
TypeScriptで記載されたSeedファイルを実行するため、v7以前ではpackage.jsonに以下のような記載をれていましたが、これが不要になりました。というか、あるとエラーになります。
"prisma": {
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
},
またこの構成の場合は、以下のパッケージが新たに必要な構成になっているのでdependenciesに追加します。
- @prisma/adapter-pg
- dotenv
- pg
- tsx
schema.prismaの変更点とprisma.config.tsの追加
v7の大きい変更点は生成されるクライアントファイルの管理が必要になったところだと思います。
冒頭で記載したように以前はnode_modulesに配置されていたものが、リポジトリ管理ファイルとして保持するものに変更されています。
そのためschema.prismaに以下のような変更が必要になります。
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearch"]
}
datasource db {
provider = "postgresql"
}
generator client {
provider = "prisma-client"
output = "./generated/prisma"
moduleFormat = "esm"
generatedFileExtension = "ts"
importFileExtension = "ts"
previewFeatures = ["fullTextSearchPostgres"]
}
ちなみにgeneratedFileExtensionやimportFileExtensionあたりの設定がないと、TypeScript環境では実行時にファイルが見つからない系エラーが発生します。
そしてprisma.config.tsファイルを新規追加します。
import 'dotenv/config';
import path from 'node:path';
import { defineConfig, env } from 'prisma/config';
export default defineConfig({
schema: path.join(__dirname, 'prisma/schema.prisma'),
migrations: {
path: path.join(__dirname, 'prisma/migrations'),
seed: 'tsx prisma/seed.ts',
},
datasource: {
url: env('DATABASE_URL'),
},
});
モノレポ構成でのポイントは、「パスの指定に__dirnameを使う必要があるが、seedコマンドは相対パスで書く」ところです。
seed.tsの変更点
seed.tsも以前は事前準備が、以下のように2行で済むお手軽構成でしたが、
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
v7からはadapterの定義が必要になっています。
例えばカテゴリデータをを入れるようなコードは以下のようになります。
import { PrismaClient } from "./generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import { CATEGORIES } from "./seeds/categories";
import "dotenv/config";
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
});
const prisma = new PrismaClient({
adapter,
});
async function main() {
console.log("Seeding database...");
for (const category of CATEGORIES) {
await prisma.category.upsert({
where: { name: category.name },
update: {},
create: category,
});
}
console.log(`Created ${CATEGORIES.length} categories`);
console.log("Seeding completed.");
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
tsconfig.jsonは変更不要
ちなみにtsconfig.jsonは変更が不要でした。今使っている全量はこちらです。
{
"compilerOptions": {
"target": "es6",
"lib": ["dom", "dom.iterable", "es6", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"types": ["node"],
"typeRoots": ["./node_modules/@types", "../../node_modules/@types"],
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"paths": { "@/*": ["./*"] },
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"incremental": true,
"sourceMap": true,
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "dist"
},
"include": ["prisma/**/*.ts"],
"exclude": ["node_modules"]
}
apps/web側の変更点
Next.jsアプリケーション側の変更点は
- PrismaClientのimport変更
- dependenciesに
"@sample-app/db: "*",を追加
になります。
Prisma管理パッケージの名前が"@sample-app/db"で、ファイルの生成先がprisma/generated/prismaとした場合、package.jsonのdependenciesに"@sample-app/db: "*",を追加し、PrismaClientのインスタンスを生成しているファイルでimport先を以下のように変更してください。
import { PrismaClient } from "@sample-app/db/prisma/generated/prisma/client";
運用上の注意
Prismaパッケージのバージョンを上げると、古い生成コードが使えなくな(る場合があ)ります。
✓ Starting...
✓ Ready in 436ms
⨯ TypeError: Cannot read properties of undefined (reading 'graph')
at createPrismaClient (src/lib/prisma.ts:27:10)
at <unknown> (src/lib/prisma.ts:30:42)
25 | });
26 |
> 27 | return new PrismaClient({ adapter });
| ^
28 | };
29 |
30 | const prisma = globalForPrisma.prisma || createPrismaClient(); {
clientVersion: '7.3.0'
}
なので私みたいにしれっとリポジトリ管理してしまわず、.gitignoreにクライアントが生成されるディレクトリを追加しておきましょう。。。
いやでもこれは、マイグレーションガイドの方にも書いておいてくれても!良かったと思う!よ!なんて。