{"id":13485019,"url":"https://github.com/belgattitude/nextjs-monorepo-example","last_synced_at":"2025-05-14T02:04:31.448Z","repository":{"id":37014305,"uuid":"288381626","full_name":"belgattitude/nextjs-monorepo-example","owner":"belgattitude","description":"Collection of monorepo tips \u0026 tricks ","archived":false,"fork":false,"pushed_at":"2025-04-24T10:43:21.000Z","size":300794,"stargazers_count":1730,"open_issues_count":17,"forks_count":230,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-05-11T17:05:23.069Z","etag":null,"topics":["example","monorepo","nextjs","tutorial","typescript","vercel","vite","workspace","workspaces","yarn"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/belgattitude.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"belgattitude","ko_fi":"belgattitude"}},"created_at":"2020-08-18T07:07:20.000Z","updated_at":"2025-05-10T21:39:51.000Z","dependencies_parsed_at":"2023-10-13T07:46:47.342Z","dependency_job_id":"e8aad306-b4ba-48d9-94e3-9c072031210f","html_url":"https://github.com/belgattitude/nextjs-monorepo-example","commit_stats":{"total_commits":7287,"total_committers":14,"mean_commits":520.5,"dds":0.5335529024289831,"last_synced_commit":"481c460eeffc08b4c7090b4b1a7c6c20eefd33a2"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/belgattitude%2Fnextjs-monorepo-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/belgattitude%2Fnextjs-monorepo-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/belgattitude%2Fnextjs-monorepo-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/belgattitude%2Fnextjs-monorepo-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/belgattitude","download_url":"https://codeload.github.com/belgattitude/nextjs-monorepo-example/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254052668,"owners_count":22006716,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["example","monorepo","nextjs","tutorial","typescript","vercel","vite","workspace","workspaces","yarn"],"created_at":"2024-07-31T17:01:42.830Z","updated_at":"2025-05-14T02:04:31.426Z","avatar_url":"https://github.com/belgattitude.png","language":"TypeScript","funding_links":["https://github.com/sponsors/belgattitude","https://ko-fi.com/belgattitude"],"categories":["TypeScript","vite","🌐 Web Development - Frontend"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003e\u003ca aria-label=\"NextJs Monorepo\" href=\"https://github.com/belgattitude/nextjs-monorepo-example\"\u003eNextJs Monorepo\u003c/a\u003e\u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\u003cstrong\u003eMonorepo concepts, tips and tricks oriented around NextJs\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca aria-label=\"Build\" href=\"https://github.com/belgattitude/nextjs-monorepo-example/actions?query=workflow%3ACI\"\u003e\n    \u003cimg alt=\"GitHub branch checks state\" src=\"https://img.shields.io/github/checks-status/belgattitude/nextjs-monorepo-example/main?label=CI\u0026logo=github\u0026style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"Codefactor grade\" href=https://www.codefactor.io/repository/github/belgattitude/nextjs-monorepo-example\"\u003e\n    \u003cimg alt=\"Codefactor\" src=\"https://img.shields.io/codefactor/grade/github/belgattitude/nextjs-monorepo-example?label=Codefactor\u0026logo=codefactor\u0026style=flat-quare\u0026labelColor=000000\" /\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"CodeClimate maintainability\" href=\"https://codeclimate.com/github/belgattitude/nextjs-monorepo-example\"\u003e\n    \u003cimg alt=\"Maintainability\" src=\"https://img.shields.io/codeclimate/maintainability/belgattitude/nextjs-monorepo-example?label=Maintainability\u0026logo=code-climate\u0026style=flat-quare\u0026labelColor=000000\" /\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"CodeClimate technical debt\" href=\"https://codeclimate.com/github/belgattitude/nextjs-monorepo-example\"\u003e\n    \u003cimg alt=\"Techdebt\" src=\"https://img.shields.io/codeclimate/tech-debt/belgattitude/nextjs-monorepo-example?label=TechDebt\u0026logo=code-climate\u0026style=flat-quare\u0026labelColor=000000\" /\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"Codacy grade\" href=\"https://www.codacy.com/gh/belgattitude/nextjs-monorepo-example/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=belgattitude/nextjs-monorepo-example\u0026amp;utm_campaign=Badge_Grade\"\u003e\n    \u003cimg alt=\"Codacy grade\" src=\"https://img.shields.io/codacy/grade/dff9c944af284a0fad4e165eb1727467?logo=codacy\u0026style=flat-square\u0026labelColor=000\u0026label=Codacy\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"LoC\"\u003e  \n    \u003cimg alt=\"LoC\" src=\"https://img.shields.io/tokei/lines/github/belgattitude/nextjs-monorepo-example?style=flat-quare\u0026labelColor=000000\" /\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"Top language\" href=\"https://github.com/belgattitude/nextjs-monorepo-example/search?l=typescript\"\u003e\n    \u003cimg alt=\"GitHub top language\" src=\"https://img.shields.io/github/languages/top/belgattitude/nextjs-monorepo-example?style=flat-square\u0026labelColor=000\u0026color=blue\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"Licence\" href=\"https://github.com/belgattitude/nextjs-monorepo-example/blob/main/LICENSE\"\u003e\n    \u003cimg alt=\"Licence\" src=\"https://img.shields.io/github/license/belgattitude/nextjs-monorepo-example?style=flat-quare\u0026labelColor=000000\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003e Howtos for monorepo. New to monorepos ? [check this FAQ](./README.md#monorepo). This example is managed by turborepo and yarn 4 with a\n\u003e / [typescript path aliases](https://www.typescriptlang.org/tsconfig#paths) approach. Not the only way to do.\n\nUseful to\n\n- Establish a **structure** and present a lifecycle perspective (dx, ci/cd, deployments...)\n- How to create and consume **shared packages**, locales, assets, api types...\n- Integrate **tools \u0026 configs** (eslint, jest, playwright, storybook, changelogs, versioning, codecov, codeclimate...).\n- Clarify some **advantages** of monorepos (team cohesion, consistency, duplication, refactorings, atomic commits...).\n- Create nextjs/vercel/prisma... bug reports with **reproducible examples** _(initial goal of this repo)_.\n\n## Sponsors ❤️\n\nIf you are enjoying some of my OSS work in your company, I'd really appreciate a [sponsorship](https://github.com/sponsors/belgattitude), a [coffee](https://ko-fi.com/belgattitude) or a dropped star.\nThat gives me some more time to improve it to the next level.\n\n### Special thanks to\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://www.jetbrains.com/?ref=belgattitude\" target=\"_blank\"\u003e\n         \u003cimg width=\"65\" src=\"https://asset.brandfetch.io/idarKiKkI-/id53SttZhi.jpeg\" alt=\"Jetbrains logo\" /\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://www.embie.be/?ref=belgattitude\" target=\"_blank\"\u003e\n        \u003cimg width=\"65\" src=\"https://avatars.githubusercontent.com/u/98402122?s=200\u0026v=4\" alt=\"Jetbrains logo\" /\u003e    \n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003ca href=\"https://www.vercel.com/?ref=belgattitude\" target=\"_blank\"\u003e\n        \u003cimg width=\"65\" src=\"https://avatars.githubusercontent.com/u/14985020?s=200\u0026v=4\" alt=\"Vercel logo\" /\u003e    \n      \u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"https://www.jetbrains.com/?ref=belgattitude\" target=\"_blank\"\u003eJetBrains\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"https://www.embie.be/?ref=belgattitude\" target=\"_blank\"\u003eEmbie.be\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003ca href=\"https://vercel.com/?ref=belgattitude\" target=\"_blank\"\u003eVercel\u003c/a\u003e\n    \u003c/td\u003e\n   \u003c/tr\u003e\n\u003c/table\u003e\n\n## Install\n\n```bash\ncorepack enable\nyarn install\n```\n\n## Structure\n\n[![Open in Gitpod](https://img.shields.io/badge/Open%20In-Gitpod.io-%231966D2?style=for-the-badge\u0026logo=gitpod)](https://gitpod.io/#https://github.com/belgattitude/nextjs-monorepo-example)\n\n```\n.\n├── apps\n│   ├── nextjs-app  (i18n, ssr, api, vitest)\n│   └── vite-app\n└── packages\n    ├── common-i18n         (locales...)\n    ├── core-lib\n    ├── db-main-prisma\n    ├── eslint-config-bases (to shared eslint configs)\n    └── ui-lib              (emotion, storybook)\n```\n\n#### Example apps\n\n- [apps/nextjs-app](./apps/nextjs-app): SSR, i18n, tailwind v3, emotion, graphQL, rest... [README](./apps/nextjs-app/README.md) | [DEMO/Vercel](https://monorepo-nextjs-app.vercel.app) | [CHANGELOG](./apps/nextjs-app/CHANGELOG.md)\n- [apps/vite-app](./apps/vite-app): Basic vite-app. [README](./apps/vite-app/README.md) | [DEMO/Vercel](https://monorepo-vite-app.vercel.app) | [CHANGELOG](./apps/vite-app/CHANGELOG.md)\n\n\u003e Apps should not depend on apps, they can depend on packages\n\n#### Example shared packages\n\n- [packages/core-lib](./packages/core-lib): publishable. [README](./packages/core-lib/README.md) | [CHANGELOG](./packages/core-lib/CHANGELOG.md)\n- [packages/db-main-prisma](./packages/db-main-prisma): used by web-app. [README](./packages/db-main-prisma/README.md) | [CHANGELOG](./packages/db-main-prisma/CHANGELOG.md)\n- [packages/eslint-config-bases](./packages/eslint-config-bases): [README](./packages/eslint-config-bases/README.md) | [CHANGELOG](./packages/eslint-config-bases/CHANGELOG.md)\n- [packages/ui-lib](./packages/ui-lib): publishable. [README](./packages/ui-lib/README.md) | [CHANGELOG](./packages/ui-lib/CHANGELOG.md)\n- [packages/common-i18n](./packages/common-i18n): [README](./packages/common-i18n/README.md) | [CHANGELOG](./packages/common-i18n/CHANGELOG.md)\n\n\u003e Apps can depend on packages, packages can depend on each others...\n\n#### Folder overview\n\n\u003cdetails\u003e\n\u003csummary\u003eDetailed folder structure\u003c/summary\u003e\n\n```\n.\n├── apps\n│   ├── vite-app                 (Vite app as an example)\n│   │   ├── src/\n│   │   ├── package.json         (define package workspace:package deps)\n│   │   └── tsconfig.json        (define path to packages)\n│   │\n│   └── nextjs-app                  (NextJS app with api-routes)\n│       ├── e2e/                 (E2E tests with playwright)\n│       ├── public/\n│       ├── src/\n│       │   └── pages/api        (api routes)\n│       ├── CHANGELOG.md\n│       ├── next.config.mjs\n│       ├── package.json         (define package workspace:package deps)\n│       ├── tsconfig.json        (define path to packages)\n│       └── vitest.config.ts\n│\n├── packages\n│   ├── core-lib                 (basic ts libs)\n│   │   ├── src/\n│   │   ├── CHANGELOG.md\n│   │   ├── package.json\n│   │   └── tsconfig.json\n│   │\n│   ├── db-main-prisma          (basic db layer with prisma)\n│   │   ├── e2e/                (E2E tests)\n│   │   ├── prisma/\n│   │   ├── src/\n│   │   ├── CHANGELOG.md\n│   │   ├── package.json\n│   │   └── tsconfig.json\n│   │\n│   ├── eslint-config-bases\n│   │   ├── src/\n│   │   ├── CHANGELOG.md\n│   │   ├── package.json\n│   │   └── tsconfig.json\n│   │\n│   └── ui-lib                  (basic design-system in react)\n│       ├── src/\n│       ├── CHANGELOG.md\n│       ├── package.json\n│       └── tsconfig.json\n│\n├── static                       (no code: images, json, locales,...)\n│   ├── assets\n│   └── locales\n├── docker                       (docker...)\n│   ├── .dockerignore\n│   ├── docker-compose.yml       (compose specific for nextjs-app)\n│   ├── docker-compose.db.yml    (general services like postgresql...)\n│   └── Dockerfile               (multistage build for nextjs-app)\n├── .yarnrc.yml\n├── package.json                 (the workspace config)\n└── tsconfig.base.json           (base typescript config)\n```\n\n\u003c/details\u003e\n\n## Howto\n\n### 1. Enable workspace support\n\n\u003cdetails\u003e\n\u003csummary\u003eRoot package.json with workspace directories\u003c/summary\u003e\n\n```json5\n{\n  \"name\": \"nextjs-monorepo-example\",\n  // Set the directories where your apps, packages will be placed\n  \"workspaces\": [\"apps/*\", \"packages/*\"],\n  //...\n}\n```\n\n_The package manager will scan those directories and look for children `package.json`. Their\ncontent is used to define the workspace topology (apps, libs, dependencies...)._\n\n\u003c/details\u003e\n\n### 2. Create a new package\n\nCreate a folder in [./packages/](./packages) directory with the name of\nyour package.\n\n\u003cdetails\u003e\n   \u003csummary\u003eCreate the package folder\u003c/summary\u003e\n\n```bash\nmkdir packages/magnificent-poney\nmkdir packages/magnificent-poney/src\ncd packages/magnificent-poney\n```\n\n\u003c/details\u003e\n\nInitialize a package.json with the name of your package.\n\n\u003e Rather than typing `yarn init`, prefer to take the [./packages/ui-lib/package.json](./packages/ui-lib/package.json)\n\u003e as a working example and edit its values.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample of package.json\u003c/summary\u003e\n\n```json5\n{\n  \"name\": \"@your-org/magnificent-poney\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"clean\": \"rimraf ./tsconfig.tsbuildinfo\",\n    \"lint\": \"eslint . --ext .ts,.tsx,.js,.jsx\",\n    \"typecheck\": \"tsc --project ./tsconfig.json --noEmit\",\n    \"test\": \"run-s 'test:*'\",\n    \"test:unit\": \"echo \\\"No tests yet\\\"\",\n    \"fix:staged-files\": \"lint-staged --allow-empty\",\n    \"fix:all-files\": \"eslint . --ext .ts,.tsx,.js,.jsx --fix\",\n  },\n  \"devDependencies\": {\n    \"@your-org/eslint-config-bases\": \"workspace:^\",\n  },\n}\n```\n\n\u003c/details\u003e\n\n### 3. Using the package in app\n\n#### Step 3.1: package.json\n\nFirst add the package to the app package.json. The recommended way is to\nuse the [workspace protocol](https://yarnpkg.com/features/protocols#workspace) supported by\nyarn and pnpm.\n\n```bash\ncd apps/my-app\nyarn add @your-org/magnificent-poney@'workspace:^'\n```\n\nInspiration can be found in [apps/nextjs-app/package.json](./apps/nextjs-app/package.json).\n\n\u003cdetails\u003e\n\u003csummary\u003epackage.json\u003c/summary\u003e\n\n```json5\n{\n  \"name\": \"my-app\",\n  \"dependencies\": {\n    \"@your-org/magnificient-poney\": \"workspace:^\",\n  },\n}\n```\n\n\u003c/details\u003e\n\n#### Step 3.2: In tsconfig.json\n\nThen add a typescript path alias in the app tsconfig.json. This\nwill allow you to import it directly (no build needed)\n\nInspiration can be found in [apps/nextjs-app/tsconfig.json](./apps/nextjs-app/tsconfig.json).\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample of tsonfig.json\u003c/summary\u003e\n\n```json5\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \"./src\",\n    \"paths\": {\n      // regular app aliases\n      \"@/components/*\": [\"./components/*\"],\n      // packages aliases, relative to app_directory/baseUrl\n      \"@your-org/magnificent-poney/*\": [\n        \"../../../packages/magnificent-poney/src/*\",\n      ],\n      \"@your-org/magnificent-poney\": [\n        \"../../../packages/magnificent-poney/src/index\",\n      ],\n    },\n  },\n}\n```\n\n\u003e PS:\n\u003e\n\u003e - Don't try to set aliases in the global tsonfig.base.json to keep strict with\n\u003e   graph dependencies.\n\u003e - The **star** in `@your-org/magnificent-poney/*` allows you to import subfolders. If you use\n\u003e   a barrel file (index.ts), the alias with star can be removed.\n\n\u003c/details\u003e\n\n#### Step 3.3: Next config\n\nEdit your `next.config.mjs` and enable the [experimental.externalDir option](https://github.com/vercel/next.js/pull/22867).\nFeedbacks [here](https://github.com/vercel/next.js/discussions/26420).\n\n```js\nconst nextConfig = {\n  experimental: {\n    externalDir: true,\n  },\n};\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eUsing a NextJs version prior to 10.2.0 ?\u003c/summary\u003e\n\nIf you're using an older NextJs version and don't have the experimental flag, you can simply override your\nwebpack config.\n\n```js\nconst nextConfig = {\n  webpack: (config, { defaultLoaders }) =\u003e {\n    // Will allow transpilation of shared packages through tsonfig paths\n    // @link https://github.com/vercel/next.js/pull/13542\n    const resolvedBaseUrl = path.resolve(config.context, \"../../\");\n    config.module.rules = [\n      ...config.module.rules,\n      {\n        test: /\\.(tsx|ts|js|jsx|json)$/,\n        include: [resolvedBaseUrl],\n        use: defaultLoaders.babel,\n        exclude: (excludePath) =\u003e {\n          return /node_modules/.test(excludePath);\n        },\n      },\n    ];\n    return config;\n  },\n};\n```\n\n\u003c/details\u003e\n\n\u003e PS: If your shared package make use of scss bundler... A custom webpack configuration will be necessary\n\u003e or use [next-transpile-modules](https://github.com/martpie/next-transpile-modules), see FAQ below.\n\n#### Step 3.4: Using the package\n\nThe packages are now linked to your app, just import them like regular packages: `import { poney } from '@your-org/magnificent-poney'`.\n\n### 4. Publishing\n\n\u003e Optional\n\nIf you need to share some packages outside of the monorepo, you can publish them to npm or private repositories.\nAn example based on microbundle is present in each package. Versioning and publishing can be done with [atlassian/changeset](https://github.com/atlassian/changesets),\nand it's simple as typing:\n\n```bash\n$ yarn g:changeset\n```\n\nFollow the instructions... and commit the changeset file. A \"Version Packages\" P/R will appear after CI checks.\nWhen merging it, a [github action](./.github/workflows/release-or-version-pr.yml) will publish the packages\nwith resulting semver version and generate CHANGELOGS for you.\n\n\u003e PS:\n\u003e\n\u003e - Even if you don't need to publish, changeset can maintain an automated changelog for your apps. Nice !\n\u003e - To disable automatic publishing of some packages, just set `\"private\": \"true\"` in their package.json.\n\u003e - Want to tune the behaviour, see [.changeset/config.json](./.changeset/config.json).\n\n## 4. Monorepo essentials\n\n### Monorepo scripts\n\nSome convenience scripts can be run in any folder of this repo and will call their counterparts defined in packages and apps.\n\n| Name                         | Description                                                                           |\n| ---------------------------- | ------------------------------------------------------------------------------------- |\n| `yarn g:changeset`           | Add a changeset to declare a new version                                              |\n| `yarn g:codegen`             | Run codegen in all workspaces                                                         |\n| `yarn g:typecheck`           | Run typechecks in all workspaces                                                      |\n| `yarn g:lint`                | Display linter issues in all workspaces                                               |\n| `yarn g:lint --fix`          | Attempt to run linter auto-fix in all workspaces                                      |\n| `yarn g:lint-styles`         | Display css stylelint issues in all workspaces                                        |\n| `yarn g:lint-styles --fix`   | Attempt to run stylelint auto-fix issues in all workspaces                            |\n| `yarn g:test`                | Run unit and e2e tests in all workspaces                                              |\n| `yarn g:test-unit`           | Run unit tests in all workspaces                                                      |\n| `yarn g:test-e2e`            | Run e2e tests in all workspaces                                                       |\n| `yarn g:build`               | Run build in all workspaces                                                           |\n| `yarn g:clean`               | Clean builds in all workspaces                                                        |\n| `yarn g:check-dist`          | Ensure build dist files passes es2017 (run `g:build` first).                          |\n| `yarn g:check-size`          | Ensure browser dist files are within size limit (run `g:build` first).                |\n| `yarn clean:global-cache`    | Clean tooling caches (eslint, jest...)                                                |\n| `yarn deps:check --dep dev`  | Will print what packages can be upgraded globally (see also [.ncurc.yml](.ncurc.yml)) |\n| `yarn deps:update --dep dev` | Apply possible updates (run `yarn install \u0026\u0026 yarn dedupe` after)                      |\n| `yarn install:playwright`    | Install playwright for e2e                                                            |\n| `yarn dedupe`                | Built-in yarn deduplication of the lock file                                          |\n\n\u003e Why using `:` to prefix scripts names ? It's convenient in yarn 3+, we can call those scripts from any folder in the monorepo.\n\u003e `g:` is a shortcut for `global:`. See the complete list in [root package.json](./package.json).\n\n### Maintaining deps updated\n\nThe global commands `yarn deps:check` and `yarn deps:update` will help to maintain the same versions across the entire monorepo.\nThey are based on the excellent [npm-check-updates](https://github.com/raineorshine/npm-check-updates)\n(see [options](https://github.com/raineorshine/npm-check-updates#options), i.e: `yarn check:deps -t minor`).\n\n\u003e After running `yarn deps:update`, a `yarn install` is required. To prevent\n\u003e having duplicates in the yarn.lock, you can run `yarn dedupe --check` and `yarn dedupe` to\n\u003e apply deduplication. The duplicate check is enforced in the example github actions.\n\n## 5. Quality\n\n### 5.1 Linters\n\nSee an example in [./apps/nextjs-app/.eslintrc.js](./apps/nextjs-app/.eslintrc.js) and our\n[eslint-config-bases](./packages/eslint-config-bases/README.md).\n\n### 5.2 Hooks / Lint-staged\n\nCheck the [.husky](./.husky) folder content to see what hooks are enabled. Lint-staged is used to guarantee\nthat lint and prettier are applied automatically on commit and/or pushes.\n\n### 5.3 Tests\n\nTests relies on ts-jest or vitest depending on the app. All setups supports typescript path aliases.\nReact-testing-library is enabled whenever react is involved.\n\nConfiguration lives in the root folder of each apps/packages. As an\nexample see\n\n- [./apps/nextjs-app/vitest.config.ts](./apps/nextjs-app/vitest.config.ts).\n\n### 5.4 CI\n\nYou'll find some example workflows for github action in [.github/workflows](./.github/workflows).\nBy default, they will ensure that\n\n- You don't have package duplicates.\n- You don't have typecheck errors.\n- You don't have linter / code-style errors.\n- Your test suite is successful.\n- Your apps (nextjs) or packages can be successfully built.\n- Basic check-size example in nextjs-app.\n\nEach of those steps can be opted-out.\n\nTo ensure decent performance, those features are present in the example actions:\n\n- **Caching** of packages (node_modules...) - install around 25s\n- **Caching** of nextjs previous build - built around 20s\n- **Triggered when changed** using [actions paths](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestpaths), ie:\n\n  \u003e ```\n  \u003e  paths:\n  \u003e    - \"apps/nextjs-app/**\"\n  \u003e    - \"packages/**\"\n  \u003e    - \"package.json\"\n  \u003e    - \"tsconfig.base.json\"\n  \u003e    - \"yarn.lock\"\n  \u003e    - \".yarnrc.yml\"\n  \u003e    - \".github/workflows/**\"\n  \u003e    - \".eslintrc.base.json\"\n  \u003e    - \".eslintignore\"\n  \u003e ```\n\n## 6. Editor support\n\n### 6.1 VSCode\n\nThe ESLint plugin requires that the `eslint.workingDirectories` setting is set:\n\n```\n\"eslint.workingDirectories\": [\n    {\n        \"pattern\": \"./apps/*/\"\n    },\n    {\n        \"pattern\": \"./packages/*/\"\n    }\n],\n```\n\nMore info [here](https://github.com/microsoft/vscode-eslint#mono-repository-setup)\n\n## 7. Deploy\n\n### Vercel\n\nVercel support natively monorepos, see the [vercel-monorepo-deploy](./docs/deploy/deploy-vercel.md) document.\n\n### Docker\n\nThere's a basic example for building a docker image, read the [docker doc](./docs/docker/docker.md).\n\n### Others\n\nNetlify, aws-amplify, k8s-docker, serverless-nextjs recipes might be added in the future. PR's welcome too.\n\n## FAQ\n\n### Monorepo\n\n#### Benefits\n\n- [x] **Ease of code reuse.** You can easily extract shared libraries (like api, shared ui, locales, images...) and use them across apps without\n      the need of handling them in separate git repos (removing the need to publish, version, test separately...). This limit the tendency to create code duplication\n      amongst developers when time is short.\n- [x] **Atomic commits.** When projects that work together are contained in separate repositories, releases need to sync which versions of one project work\n      with the other. In monorepo CI, sandboxes and releases are much easier to reason about (ie: [dependency hell](https://en.wikipedia.org/wiki/Dependency_hell)...).\n      A pull-request contains all changes at once, no need to coordinate multiple packages versions to test it integrally (multiple published canary versions...).\n- [x] **Code refactoring.** Changes made on a library will immediately propagate to all consuming apps / packages.\n      Typescript / typechecks, tests, ci, sandboxes... will improve the confidence to make a change _(or the right one thanks to improved discoverability of\n      possible side effects)_. It also limits the tendency to create tech debt as it invites the dev to refactor all the code that depends on a change.\n- [x] **Collaboration across teams**. Consistency, linters, discoverability, duplication... helps to maintain\n      cohesion and collaboration across teams.\n\n#### Drawbacks\n\n- [x] **Increased build time**. Generally a concern but not relevant in this context thanks to the combination of\n      nextjs/webpack5, typescript path aliases and yarn. Deps does\n      not need to be build... modified files are included as needed and properly cached (nextjs webpack5, ci, deploy, docker/buildkit...).\n- [x] **Versioning and publishing**. Sometimes a concern when you want to use the shared libraries outside of the monorepo.\n      See the notes about [atlassian changeset](https://github.com/atlassian/changesets). Not relevant here.\n- [x] **Git repo size**. All packages and apps and history will fit in the same git repository increasing its size and\n      checkout time. Generally when you reach size problems, check for assets like images first and extract\n      packages that don't churn anymore.\n- [x] **Multi-languages**. Setting up a monorepo containing code in multiple languages (php, ruby, java, node) is extremely\n      difficult to handle due to nonexistence of mature tooling (bazel...).The general idea is\n      to create a monorepo with the same stack (node, typescript...) and managed by the same\n      package manager (yarn, pnpm,...)\n\n#### Exact vs semver dependencies\n\nApps dependencies and devDependencies are pinned to exact versions. Packages deps will use semver compatible ones.\nFor more info about this change see [reasoning here](https://docs.renovatebot.com/dependency-pinning/) and our\n[renovabot.json5](renovate.json5) configuration file.\n\nTo help keeping deps up-to-date, see the `yarn deps:check \u0026\u0026 yarn deps:update` scripts and / or use the [renovatebot](https://github.com/marketplace/renovate).\n\n\u003e When adding a dep through yarn cli (i.e.: yarn add something), it's possible to set the save-exact behaviour automatically\n\u003e by setting `defaultSemverRangePrefix: \"\"` in [yarnrc.yml](./.yarnrc.yml). But this would make the default for packages/\\* as well.\n\u003e Better to handle `yarn add something --exact` on per-case basis.\n\n## License\n\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fbelgattitude%2Fnextjs-monorepo-example.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fbelgattitude%2Fnextjs-monorepo-example?ref=badge_large)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbelgattitude%2Fnextjs-monorepo-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbelgattitude%2Fnextjs-monorepo-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbelgattitude%2Fnextjs-monorepo-example/lists"}