Publish from a monorepo
Keep several independently versioned Typeship Targets beside your application code and publish each package from one repository workflow.
Several Targets can share one repository while keeping separate versions and releases. Give each Target a non-overlapping directory, then configure the repository's publishing workflow for each package.
You need a Project, write access to the destination repository, the GitHub App installed there, and permission to configure the packages' trusted publishers. Start with Publish your packages for the release model.
Choose a repository layout
Typeship supports three common layouts. The release model is identical in each; only the Delivery repository and directory change.
| Layout | Use it when | Example |
|---|---|---|
| Source and generated packages together | The API team owns application and SDK changes in one review graph. | apps/api, packages/sdk, packages/cli |
| Dedicated generated-products monorepo | One platform team owns every public client, separate from application deploys. | packages/typescript, packages/python, tools/cli |
| One repository per Target | Package permissions, release cadence, or external contributors differ. | acme/sdk-ts, acme/sdk-python, acme/cli |
Do not split repositories merely to get independent versions. Target identity, not repository identity, is the release boundary.
apps/api/ # your source application
openapi.yaml # the Definition entrypoint
packages/typescript/ # Target A
packages/python/ # Target B
tools/acme/ # Target C (CLI)
.typeship/targets/ # one manifest per Target
.github/workflows/typeship-release.ymlConfigure non-overlapping Deliveries
[
{
"name": "Acme TypeScript SDK",
"generator": "typescript-sdk",
"deliveries": [{
"kind": "repository",
"repository": {"provider": "github", "identifier": "acme/platform"},
"directory": "packages/typescript",
"package_name": "@acme/sdk",
"publish_on_merge": true
}]
},
{
"name": "Acme Python SDK",
"generator": "python-sdk",
"deliveries": [{
"kind": "repository",
"repository": {"provider": "github", "identifier": "acme/platform"},
"directory": "packages/python",
"package_name": "acme-python",
"publish_on_merge": true
}]
}
]A Target owns its generated directory. Typeship rejects the repository root beside any other Target, identical directories, and parent/child overlaps such as packages plus packages/python. Sibling paths are safe.
Review and merge independently
Each changed Target has one rolling Draft PR. Several Definition commits may update it before the team is ready to release. Merge only the package you want to make Current; the others continue accumulating changes against their own Current releases.
For example, suppose the TypeScript SDK is Current at 2.4.0 and the Python SDK is Current at 1.8.2:
| Event | TypeScript Target | Python Target |
|---|---|---|
| Monday: add pagination | Draft becomes 2.5.0 | Draft becomes 1.9.0 |
| Tuesday: improve pagination docs | Same Draft updates; still 2.5.0 | Same Draft updates; still 1.9.0 |
| Wednesday: remove a response field | Same Draft now requires 3.0.0 | Same Draft now requires 2.0.0 |
| Thursday: merge only TypeScript | 3.0.0 becomes Current and publishes | 1.8.2 remains Current; Draft 2.0.0 stays open |
| Next Tuesday: merge Python | No change | 2.0.0 becomes Current and publishes |
The three source commits became one reviewed TypeScript release, not three package releases. Python used the same source history but kept its own review date, version, and registry outcome.
The first publish-enabled Draft installs the root release and republish workflows plus VERSIONING.md. Those files then belong to the repository: Typeship leaves existing copies alone, so a sibling Draft cannot roll back a team's workflow customization. Each later Draft changes only its own .typeship/targets/<target-id>.json manifest and generated directory. After GitHub records the merge, Typeship dispatches one release run with that exact Target, version, and accepted commit; publishing uses that accepted commit.
Integrate the workspace
Add generated JavaScript packages to the root workspaces/pnpm/Yarn configuration and keep the lockfile at the repository root if that is already the monorepo convention. The publishing workflow runs inside the Target directory, so package-local build and test scripts remain the contract. Python and Go Targets can coexist without joining the JavaScript workspace.
Shared lockfiles, workspace configuration, and root build orchestration remain repository-owned. Typeship snapshots and merges each Target directory; it does not infer that a package dependency also requires a root lockfile change. Commit a required shared-file update normally on that Target's rolling Draft, and configure the root workspace install, build, or policy status in checks.repository_required. The exact Draft cannot become ready until each named status reports success.
Required checks are evaluated per Target head. A shared dependency failure blocks the affected Target even when a sibling is green, and a failure on one Target does not make another Target's evidence reusable. Configure the same named repository check on every Target that depends on it.
When a sibling Draft merges, the destination default branch advances. Typeship re-integrates other rolling Drafts from that new default commit, while continuing to snapshot only their own Target directories. This updates their starting commit and reruns their checks without claiming the merged sibling package, shared lockfile, or root configuration as generated files.
Avoid regeneration loops: point the Project Definition at authored API source, never at a generated package file; ignore typeship/update-* branches in source-trigger automation; and do not make a package publish update the Definition version. OpenAPI info.version is API metadata, not the Target's package version.
When one source change affects several Targets, Typeship updates each rolling Draft independently. Teams can merge those PRs together in a release train or across different days. There is no cross-Target version transaction: a failed Python publication does not block a successful TypeScript publication.
Configure trusted publishers
Registry trust is attached to the repository and workflow filename, not to Typeship:
- Configure each npm or PyPI package to trust
acme/platformandtypeship-release.yml. - Protect the
typeship-releaseenvironment. Use required reviewers when publication needs a human gate after merge. - Require package tests and
Typeship – release readinessbefore merging each Draft. - Keep custom application and orchestration code outside generated Target directories.
Go submodules use directory-prefixed tags such as packages/go/v1.4.0. The generated workflow derives the prefix from the Target manifest.
List all Targets before choosing a directory. Reuse a Target when package identity and release history should remain the same; create another Target only for an independent product. Never resolve a directory conflict by moving or deleting an existing Target without explicit authorization.
Move from separate repositories
Changing a Delivery repository or directory opens an updated rolling Draft and invalidates the old destination candidate. It does not rewrite release history. Configure trusted publishers for the new repository before enabling publish on merge, then merge the first Draft there to establish the new destination baseline.
Troubleshoot one Target
- No workflow after the first merge: open the Target and retry the pending Publication. Typeship dispatches the installed republish workflow with the exact accepted commit.
- Wrong package selected: compare the Target's manifest
directoryandpackage_namewith the Delivery; never edit the manifest as configuration. - Workspace install fails: run the package's normal root workspace install locally and commit any repository-owned lockfile change in a follow-up review.
- Version already exists: compare the reported artifact digest. Identical bytes are idempotent success; different bytes require a new version.
- Only one Target should release: merge only that Target's Draft. Unmerged siblings continue accumulating against their own Current.
Require workspace checks
Keep shared lockfiles, workspace configuration, and repository workflows outside the Target’s directory. Configure package checks to require existing workspace checks on every relevant Draft head. Customer commands run inside the Target’s package directory; repository-required checks must already have a workflow. Preserve the complete checks value when adding a requirement.