Skip to content

jkomyno/pnpm-monorepo-template

Repository files navigation

pnpm-monorepo-template

Github Actions

Pragmatic template for a TypeScript monorepo with pnpm, turborepo, and vitest.

Tested with:

  • Node.js v24.13.0
  • pnpm v10.28.2
  • vitest v4.0.18

Table of Contents

What's Included

  • pnpm workspace, whose configuration is stored in pnpm-workspace.yaml. Two example packages are included, common-utils and example, with the latter importing common-utils as a dependency. All local packages are decorated with a @jkomyno/* scope (you may want to substitute these instances in the name entries of any package.json with yours or your company's name).
  • tsdown bundler, whose configuration is stored in tsdown.config.base.ts.
  • turborepo, whose configuration is stored in turbo.json
  • an example Dockerfile that can be built and used as a base image for your Node.js Docker containers.
  • the vitest test engine, whose configuration is stored in vitest.config.ts.
  • opinionated linting setups via biome, whose configuration is defined in the biome.jsonc file.
  • Changesets for versioning and changelogs; the Release workflow opens a "Version Packages" PR when changesets land on main, and publishes to npm when that PR is merged using npm trusted publishing (OIDC)—no long-lived tokens. See Publishing (OIDC) below.
  • pkg.pr.new for continuous preview releases: each PR gets installable preview packages (install the GitHub App on the repo first).

Available Scripts

  • pnpm install: install the dependencies needed for each package.
  • pnpm build: typecheck and transpile the local TypeScript packages to JavaScript.
  • pnpm build:watch: transpile the local TypeScript packages to JavaScript, and watch for changes.
  • pnpm check:exports: check that the exports field in the package.json files of each exported package is correctly set, using @arethetypeswrong/cli.
  • pnpm typecheck: run type checks for packages that define a typecheck script.
  • pnpm lint:ci: check that the code follows the biome guidelines.
  • pnpm lint: check that the code follows the biome guidelines, and override it to follow them if possible.
  • pnpm lint:fix: same as pnpm lint; included as a clearer alias.
  • pnpm test:unit: run unit tests.
  • pnpm test:integration: run integration tests.
  • pnpm test: run all tests.
  • pnpm bench: run benchmarks for packages that define a bench script.
  • pnpm bench:watch: run benchmarks in watch mode for packages that define bench:watch.
  • pnpm changeset: add a new changeset (version bump + changelog entry).
  • pnpm version-packages: apply changesets (bump versions, update changelogs, then pnpm install). Used by the Release workflow.

Publishing (OIDC)

Releases use npm trusted publishing (OIDC), so you do not need an NPM_TOKEN secret. You configure npm to trust this repo's workflow once per package:

Template note: the release workflow is scaffolded but disabled by default in release.yaml. After you configure npm trusted publishing (OIDC), remove if: false and uncomment the Changesets step in that file.

  1. Publish the package manually once (if it has never been published), so it exists on npm.
  2. On npmjs.com, open the package → Package settingsTrusted Publisher.
  3. Choose GitHub Actions and set:
    • Organization or user: your GitHub org or username (e.g. jkomyno)
    • Repository: this repo name (e.g. pnpm-monorepo-template)
    • Workflow filename: release.yaml (must match exactly, including extension)
  4. Save. Future publishes from the Release workflow will use OIDC; no tokens required.

Repeat for each publishable package in the monorepo. Optional: under Publishing access, enable “Require two-factor authentication and disallow tokens” so only the trusted workflow can publish.

Test Structure

We follow an opinionated convention for storing and running tests. All tests should be written in the __tests__ directory of a local package. Moreover, unit tests should be placed in the __tests__/unit folder; similarly, integration tests should be placed in the __tests__/integration folder. This allows for easily running groups of tests (for instance, you might want to run unit tests locally, while deferring integration tests - that will probably need access to external services like Docker containers - to the CI only).

FAQ

  1. How do I add a new package to the local workspace?
  • Create a new folder $packageName in packages/. Initialize it with a tsconfig.json file (which will reference the tsconfig.base.node.json file at the root level) and a package.json file similarly to how it's done in the common-utils package.
  1. How do I add a new dependency that should be available to each package in the local workspace?

pnpm add -w $dependencyName

👤 Author

Hi, I'm Alberto Schiabel, you can follow me on:

🦄 Show your support

Give a ⭐️ if this project helped or inspired you!

📝 License

Built with ❤️ by Alberto Schiabel.
This project is MIT licensed.

About

Opinionated Node.js monorepo example with pnpm, turborepo, and vitest

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors