Monorepo setup

The repository is organized in a monorepo structure initialized using Turborepo.

A monorepo allows to keep both client and server apps in the same repository, and to share common code between them.

The apps folder contains client and server folders. Inside packages a single api-client folder contains the shared API definition for both client and server.

Monorepo contains all the code for client, server, and shared packages.
Monorepo contains all the code for client, server, and shared packages.

The root package.json defines all the shared dependencies and scripts. In this project, the only relevant shared dependency is typescript.

All the apps share some other dependencies like effect and @effect/schema, which you may consider adding as root dependencies as well. Doing this allows to have the same version of these dependencies in all the apps.

The example project instead keeps them separate.

Two turbo command have been added to the root package.json:

  • typecheck: runs the TypeScript compiler to check for any type errors in the codebase
  • test: runs the test script in all the apps that have it defined (only server in this example)
package.json
"scripts": {
  "build": "turbo build",
  "dev": "turbo dev",
  "lint": "turbo lint",
  "typecheck": "turbo typecheck",
  "test": "turbo test",
  "format": "prettier --write \"**/*.{ts,tsx,md}\""
}

Other than that, the monorepo configuration doesn't differ much from the initial turborepo setup. I generally prefer to keep the configuration minimal, and only add features when necessary.

You may also consider other monorepo tools like Nx or Lerna.