nestjsprismamonorepoyarn-workspacesturborepo

How to create a shared package in a Turborepo (monorepo), for prisma generated models and types?


I am creating a monorepo using Turborepo consisting of multiple Nestjs microservices, and an API gateway to act as the request distributer. In each microservice, Postgres is used as a database and Prisma as the ORM. Each microservice has its own schema + Prisma client, so it's not a shared schema/client.

We are looking to create a shared package for things like DTOs, as well as prisma generated types and entities. The package would be shared among all microservices so if I would export the prisma generated from the microservices to the package, a cyclic dependency occurs.

I am new to monorepos so this is a complex topic for me to begin with, but I am hoping someone here on Stackoverflow may have some input on the matter. Appreciate it!


Solution

  • We have a similar monorepo regarding Prisma and Turborepo. From our point of view there are two solutions how to avoid cyclic dependencies in a monorepo:

    1. Avoid it

    Instead of creating a a shared package for all DTOs, types, etc. that should be used by all packages, leave the DTOs, types etc. inside the packages they come from.

    Sometimes it helps to rethink the sizing of the packages. The solution could be to merge some packages to one if they use the same shared code. Or to divide a package into smaller ones, if you only need a small portion of the package to be shared.

    2. Break cyclic dependencies by extra build script

    If solution 1 is not possible you can add an extra build script that copies the shared content from the packages into the shared one. In Turborepo you can either have a global script prefixed with //# that does the job, or you can add the script to each packages, or even both:

    // turbo.json
    {
      "$schema": "https://turborepo.org/schema.json",
      "pipeline": {
        "build": {
          "dependsOn": [
            "^build",
            "extraBuildScriptFromPackages",
            "//#extraGlobalBuildScript"
          ],
    // ...
        }
      }
    }
    

    We use solution 2 to collect all metadata from our packages and create a shared metadata package for the whole monorepo.

    For Prisma types we use a mix of solution 1 (for the prisma types) and solution 2 (for the resulting graphql types).