---
title: "Publish from a monorepo"
description: "Keep several independently versioned Typeship Targets beside your application code and publish each package from one repository workflow."
url: https://typeship.dev/docs/guides/publish-from-a-monorepo
markdown: https://typeship.dev/docs/guides/publish-from-a-monorepo.md
section: "Releases"
---
> ## Documentation index
> Fetch the documentation index at https://typeship.dev/llms.txt or every prose page and both generated references at https://typeship.dev/llms-full.txt.
> Append .md to any prose docs URL, or send Accept: text/markdown, for the markdown twin of that page.
> Select existing code examples with Accept-Code-Language: typescript, python, or go (one value), or add ?codeLanguage=python to a Markdown URL. The query parameter takes precedence. Unsupported values return the full docs with a notice.

# 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](https://typeship.dev/docs/guides/publish) 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.

```text
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.yml
```

## Configure non-overlapping Deliveries

```json
[
  {
    "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:

1. Configure each npm or PyPI package to trust `acme/platform` and `typeship-release.yml`.
2. Protect the `typeship-release` environment. Use required reviewers when publication needs a human gate after merge.
3. Require package tests and `Typeship – release readiness` before merging each Draft.
4. 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.

> **For AI agents:** 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 `directory` and `package_name` with 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](https://typeship.dev/docs/guides/customize#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.

## Sitemap

[Documentation index](https://typeship.dev/llms.txt)
