This is an alpha, sneak peek of Monorepo Maestros. For this iteration, I'm getting all of my thoughts down. In the future, we'll have better information architecture, graphics, and other awesomeness. Your feedback is welcome!

Workspaces

Workspaces are the fundamental “slices” of your monorepo. In a monorepo, you will create workspaces that are installable into other workspaces similar to adding a package from the npm registry.

Conventions

A typical way to set up a product-facing monorepo is to create an apps directory and a packages directory. Monorepos for libraries are often a little different because they have different needs - but the same workspacing techniques still apply.

apps

In apps, you'll find independently deployable applications that you'll ship to your users. You won't ever install an app into a different workspace; they're at the absolute top of your dependency graph.

packages

This is where we share code from. We'll install these into our applications and even other packages as needed.

tooling

Personal opinion incoming: I often like to add a tooling directory as well. In tooling, I put packages meant for the configuration of the repository rather than source code that will contribute to the code for applications. "Meta-packages" might be another way to think of these. Examples include TypeScript, ESLint, Prettier, and Tailwind configurations.

Defining workspaces

npm and Yarn create workspaces by defining them in your repo's root package.json. Once set up, your package manager will know how to identify package.json's in your code and treat them as workspaces.

To learn how to set up workspaces for your package manager, check their pages:

Anatomy of a workspace

The groundwork for understanding how a workspace can be found in package.json, the file that defines many of the characteristics of your workspaces like its name, dependencies, scripts, and exports.

package.json
{
"name": "@repo/my-package",
"version": "0.0.0",
"private": true,
"exports": {
".": "./src/index.ts"
},
"scripts": {
"format": "prettier \"**/*.{ts,tsx,md,mdx,json}\" --check",
"lint": "eslint .",
"typecheck": "tsc --noEmit"
},
"dependencies": {
// ...
},
"devDependencies": {
"@repo/lint": "workspace:*",
"@repo/prettier": "workspace:*",
"@repo/tsconfig": "workspace:*",
"typescript": "5.1.3"
}
}
package.json
{
"name": "@repo/my-package",
"version": "0.0.0",
"private": true,
"exports": {
".": "./src/index.ts"
},
"scripts": {
"format": "prettier \"**/*.{ts,tsx,md,mdx,json}\" --check",
"lint": "eslint .",
"typecheck": "tsc --noEmit"
},
"dependencies": {
// ...
},
"devDependencies": {
"@repo/lint": "workspace:*",
"@repo/prettier": "workspace:*",
"@repo/tsconfig": "workspace:*",
"typescript": "5.1.3"
}
}