Table of contents
- What is a package and why use them in monorepos
- Prerequisites
- Step‑by‑step: adding a new package
- How Graphite helps in monorepo workflows
- Best practices for new packages in monorepo
- Summary checklist
What is a package and why use them in monorepos
A package is a discrete, version‑controlled self‑contained component—like a library, service, or shared module—that lives inside the monorepo but can be built, tested, and published on its own.
Monorepo packages enable:
- Clear modularity.
- Shared code reuse.
- Streamlined dependency updates with atomic commits across packages.
- Efficient tooling like npm or yarn workspaces, Lerna, Nx, Turborepo, etc.
They're useful because they let teams logically separate concerns within one repo while supporting fine-grained CI, dependency hoisting, and version control.
Using packages provides modularity, reusability, and clear separation of responsibilities. They also support atomic changes: you can update shared logic and consumers in a single commit. Monorepos enhance this by letting packages live side by side, simplifying dependency management and code sharing.
Prerequisites
- A working git monorepo with tooling like pnpm/workspaces, yarn workspaces, or Lerna.
- Each package ideally has its own folder (e.g.,
/packages/foo/
), with apackage.json
, source code, and build/test definition. - A CI workflow that supports selective builds and tests based on changed packages.
- Optionally: Graphite installed and configured for stacked pull requests and code review optimization.
Step‑by‑step: adding a new package
1. Create the package directory
cd path/to/monorepomkdir -p packages/<new-package>cd packages/<new-package>
2. Initialize and configure package.json
npm init -y# edit package.json:# {# "name": "@your-scope/new-package",# "version": "0.1.0",# "main": "dist/index.js",# "scripts": {# "build": "tsc",# "test": "jest",# "lint": "eslint src"# }# }
Add dependencies (e.g., npm install lodash --save
or npm install typescript --save-dev
).
3. Add source files
Create standard folders:
src/index.ts # entry point__tests__/index.test.ts
Implement basic code and a test (for example, using Jest).
4. Configure the workspace
Add to repo-level configuration (package.json
or config files):
{"workspaces": ["packages/*"]}
Or add in Lerna/Turborepo/other: recognize packages/<new-package>
.
5. Install dependencies and build/test
npm installnpm run build -w @scope/new-packagenpm run test -w @scope/new-package
Verify that the package builds and passes all tests.
6. Import and integrate
- Add the new package as a dependency to another package:
npm install @your-scope/new-package --workspace=packages/consumer
- Use import in code:
import { foo } from "@your-scope/new-package";
Run consumer's build and tests to confirm integration.
7. Update CI configuration
Ensure CI runs necessary steps for the new package; for selective CI, include it in changeset logic.
8. Document the package
Add a README.md
in packages/<new-package>
with purpose, install instructions, and usage examples.
9. Commit and open a pull request
Commit changes:
git add packages/<new-package>git commit -m "feat: add new package `<new-package>`"git push origin <branch>
Open a PR. This is where Graphite shines.
How Graphite helps in monorepo workflows
Stacked pull requests Graphite allows breaking a large change (e.g. adding a package and then usage tweaks) into sequential stacked PRs, maintaining developer velocity without waiting on merges.
Merge queue & conflict prevention Graphite can rebase stacked PRs automatically and detect conflicts ahead of time, keeping the main branch green and reducing manual rebasing.
Code‑aware AI-assisted reviews (Diamond) Graphite's AI reviewer analyzes PR diffs, suggests improvements, summarizes changes, and can even propose fixes — saving reviewers' time.
CI efficiency for monorepos Graphite optimizes CI runs in monorepo setups — running builds/tests only where needed based on code changes, reducing wasteful runs.
Team coordination & visibility Unified PR inboxes, Slack notifications, and assignment tools in Graphite help distributed teams stay aligned on which packages and PRs need review.
Best practices for new packages in monorepo
- Adhere to consistent lint/build/test patterns across packages.
- Name packages clearly (
@org/foo
). - Keep scopes narrow: each package should serve a single responsibility.
- Version and update strategy: all-or-none version bumps (monolithic versioning) or independent SEMVER per package.
- Update docs (e.g., root-level index or workspace README).
Summary checklist
Step | Action |
---|---|
✅ | Create package folder |
✅ | Init package.json and scripts |
✅ | Write source and tests |
✅ | Update workspace config |
✅ | Run build and tests |
✅ | Integrate into other packages |
✅ | Adjust CI |
✅ | Write documentation |
✅ | Commit and open PR |
✅ | Use Graphite for smooth review and merging |
Adding a new package in a monorepo is a repeatable process that promotes modularity, streamlines dependency management, and encourages atomic cross-package changes. Integrating Graphite further amplifies developer efficiency by automating PR workflows, reducing merge conflicts, and scaling code review processes across teams.