> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devinenterprise.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Workspaces and monorepos

> Configure Devin's environment for monorepos, multi-package workspaces, and projects with independent subdirectories.

Monorepos and multi-package workspaces need extra care in blueprints because different subdirectories may use different languages, package managers, or dependency sets. Devin supports two approaches:

<CardGroup cols={2}>
  <Card title="Native workspaces (recommended)" icon="cubes" href="#native-workspaces">
    Create a separate blueprint for each subdirectory. Each workspace gets its own initialize, maintenance, and knowledge sections with the working directory automatically set to the subdirectory.
  </Card>

  <Card title="Subshells" icon="terminal" href="#subshells">
    Run commands in subdirectories within a single blueprint using `(cd dir && command)`. Simpler for small monorepos with only a few packages.
  </Card>
</CardGroup>

***

## Native workspaces

<Info>
  **Recommended for most monorepos.** Native workspaces give each subdirectory its own blueprint with isolated setup, knowledge, and working directory. This is cleaner and easier to maintain than subshells as the number of packages grows.
</Info>

With native workspaces, each subdirectory gets a dedicated blueprint. Commands in that blueprint run with the working directory already set to the subdirectory — no `cd` or subshells needed.

### The root blueprint

Every repo using native workspaces is expected to have a **root blueprint**. The root blueprint runs from the repository root and executes **before** any workspace-scoped blueprints. Use it for shared setup that applies across the entire repo — installing runtimes, global tools, or running root-level dependency installs.

```yaml theme={null}
# Root blueprint — runs first, from the repo root
initialize: |
  npm install -g pnpm

maintenance: |
  pnpm install
```

Workspace blueprints then handle package-specific setup and run after the root blueprint completes.

### Creating a workspace

1. Go to **Settings > Environment > Blueprints**
2. Click on the repository
3. Click **Add workspace**
4. Enter the subdirectory path (e.g., `packages/frontend`)
5. Write the blueprint for that workspace

<Warning>
  The workspace path must correspond to a real directory inside the repository. If the path does not exist when the build runs, the build will fail. Double-check that the path matches your repo structure exactly (e.g., `packages/frontend`, not `pkg/frontend`).
</Warning>

### Example

A monorepo with a React frontend and a Python backend. The root blueprint installs shared tools, then each workspace handles its own dependencies:

<Tabs>
  <Tab title="Root">
    ```yaml theme={null}
    # Root blueprint — shared setup for the entire repo
    initialize: |
      npm install -g pnpm
      curl -LsSf https://astral.sh/uv/install.sh | sh

    knowledge:
      - name: structure
        contents: |
          Monorepo with two packages:
          - packages/frontend — React app (TypeScript, pnpm)
          - packages/backend — Python API (FastAPI, uv)
    ```
  </Tab>

  <Tab title="packages/frontend">
    ```yaml theme={null}
    # Workspace scoped to packages/frontend
    maintenance: |
      pnpm install

    knowledge:
      - name: lint
        contents: pnpm lint
      - name: test
        contents: pnpm test
      - name: dev
        contents: pnpm dev
    ```
  </Tab>

  <Tab title="packages/backend">
    ```yaml theme={null}
    # Workspace scoped to packages/backend
    maintenance: |
      uv sync

    knowledge:
      - name: lint
        contents: uv run ruff check .
      - name: test
        contents: uv run pytest
      - name: dev
        contents: uv run uvicorn app.main:app --reload
    ```
  </Tab>
</Tabs>

Each workspace's `knowledge` entries are scoped to that subdirectory. When Devin works in `packages/frontend`, it sees the frontend lint/test/dev commands — not the backend ones.

### When to use native workspaces

* Subdirectories have **different languages or package managers**
* Each package needs its own **knowledge entries** (lint, test, build commands)
* You want **isolated setup** — a broken blueprint for one workspace doesn't block the others
* The number of packages is growing and a single blueprint is getting unwieldy

***

## Subshells

For simpler monorepos, you can manage everything in a single blueprint using subshells. Wrap commands in parentheses to run them in a subdirectory without affecting subsequent steps:

```yaml theme={null}
maintenance:
  - name: Frontend deps
    run: (cd packages/frontend && pnpm install)
  - name: Backend deps
    run: (cd packages/backend && uv sync)
```

The parentheses `(cd ... && ...)` create a subshell. When the subshell exits, the working directory resets to the repo root for the next step.

<Warning>
  Without parentheses, `cd` changes the working directory for all subsequent steps. Always use subshells when switching directories in blueprint steps.
</Warning>

### Why subshells matter

Compare these two approaches:

<Tabs>
  <Tab title="Correct (subshells)">
    ```yaml theme={null}
    maintenance:
      - name: Frontend deps
        run: (cd packages/frontend && pnpm install)
      - name: Backend deps
        run: (cd packages/backend && uv sync)
    ```

    Each step runs from the repo root. Both commands find the right `packages/` subdirectory.
  </Tab>

  <Tab title="Incorrect (no subshells)">
    ```yaml theme={null}
    maintenance:
      - name: Frontend deps
        run: cd packages/frontend && pnpm install
      - name: Backend deps
        run: cd packages/backend && uv sync
    ```

    The first step changes the working directory to `packages/frontend`. The second step then tries to run `cd packages/backend` relative to `packages/frontend`, which fails.
  </Tab>
</Tabs>

### When to use subshells

* The monorepo has **a few packages** with straightforward setup
* All packages share the **same language and package manager**
* You don't need per-package knowledge entries

***

## Knowledge entries for monorepos

Whether you use native workspaces or subshells, well-structured knowledge entries help Devin navigate the codebase:

```yaml theme={null}
knowledge:
  - name: structure
    contents: |
      This is a monorepo with three packages:
      - `packages/frontend` — React app (TypeScript, pnpm)
      - `packages/backend` — Python API (FastAPI, uv)
      - `packages/shared` — Shared TypeScript utilities
  - name: frontend
    contents: |
      cd packages/frontend
      Dev server: pnpm dev
      Lint: pnpm lint
      Test: pnpm test
  - name: backend
    contents: |
      cd packages/backend
      Dev server: uv run uvicorn app.main:app --reload
      Lint: uv run ruff check .
      Test: uv run pytest
```

<Tip>
  A `structure` knowledge entry that maps each directory to its language and toolchain helps Devin navigate the repo quickly. With native workspaces, each workspace has its own knowledge entries, so the `structure` entry is most useful in the root blueprint or for subshell-based setups.
</Tip>

## Examples

### Turborepo / Nx workspace

For workspaces managed by a monorepo build tool like Turborepo or Nx, install dependencies at the root and let the tool handle per-package orchestration:

```yaml theme={null}
initialize: |
  npm install -g pnpm turbo

maintenance: |
  pnpm install

knowledge:
  - name: structure
    contents: |
      Turborepo monorepo. Use `turbo` for building and testing:
      - `apps/web` — Next.js app
      - `apps/api` — Express API
      - `packages/ui` — Shared component library
      - `packages/config` — Shared configuration
  - name: build
    contents: turbo run build
  - name: test
    contents: turbo run test
  - name: lint
    contents: turbo run lint
  - name: dev
    contents: turbo run dev
```

### Multiple JDK versions

A Java monorepo where different services require different JDK versions:

```yaml theme={null}
initialize:
  - name: Install JDK 17 (primary)
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
      echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
        | sudo tee /etc/profile.d/java.sh > /dev/null

  - name: Install JDK 11 (legacy service)
    run: |
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-11-jdk-headless

maintenance:
  - name: Warm dependency caches
    run: |
      export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
      (cd services/api && ./gradlew dependencies --refresh-dependencies)

      export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
      (cd services/legacy && ./gradlew dependencies --refresh-dependencies)

knowledge:
  - name: build_api
    contents: |
      Build the API service (JDK 17):
        JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
        cd services/api && ./gradlew clean build
  - name: build_legacy
    contents: |
      Build the legacy service (JDK 11):
        JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
        cd services/legacy && ./gradlew clean build
  - name: test_all
    contents: |
      Run tests for all services:
        JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
        (cd services/api && ./gradlew test)

        JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
        (cd services/legacy && ./gradlew test)
```

### Org blueprint for shared tools

When multiple monorepo packages share the same tools, install them once in the org-wide blueprint:

```yaml theme={null}
# Org-wide blueprint (Settings > Environment > Blueprints > Org-wide setup)
initialize:
  - name: Install pnpm
    run: npm install -g pnpm
  - name: Install uv
    run: curl -LsSf https://astral.sh/uv/install.sh | sh
  - name: Install shared build tools
    run: npm install -g turbo typescript
```

Then each repo blueprint only needs project-specific commands:

```yaml theme={null}
# Repo blueprint (uses pnpm and uv from the org blueprint)
maintenance:
  - name: Install all workspace deps
    run: pnpm install
  - name: Install Python service deps
    run: (cd services/ml-pipeline && uv sync)
```

## Best practices

<AccordionGroup>
  <Accordion title="Prefer native workspaces for complex monorepos">
    When each subdirectory has its own language, package manager, or build process, native workspaces keep each blueprint focused and independent. Reserve subshells for simple cases with a few packages.
  </Accordion>

  <Accordion title="Always use subshells for directory changes">
    When using the subshell approach, wrap `cd` commands in parentheses: `(cd dir && command)`. This prevents one step's directory change from affecting the next step.
  </Accordion>

  <Accordion title="Put shared tools in the org blueprint">
    Language runtimes and package managers used across multiple repos belong in the org-wide blueprint. This avoids duplication and keeps repo blueprints focused on project-specific setup.
  </Accordion>

  <Accordion title="Order maintenance steps by dependency">
    If package A depends on package B being built first, list B's build step before A's install step in `maintenance`. Blueprint steps run sequentially in the order listed.
  </Accordion>

  <Accordion title="Add a structure knowledge entry">
    A knowledge entry named `structure` that maps directories to their languages and tools helps Devin navigate the codebase. Include which package manager each subdirectory uses and any cross-package dependencies.
  </Accordion>

  <Accordion title="Use per-package knowledge entries">
    Instead of one large knowledge entry, create separate entries for each package (e.g., `frontend`, `backend`, `ml-pipeline`). With native workspaces, each workspace has its own knowledge section built in.
  </Accordion>

  <Accordion title="Keep maintenance incremental">
    Use `pnpm install` (not `pnpm install --force`) and `uv sync` (not `rm -rf .venv && uv sync`). Incremental commands are faster during periodic rebuilds.
  </Accordion>
</AccordionGroup>

## Related pages

* [Declarative environment configuration](/onboard-devin/environment/blueprints)
* [Blueprint reference](/onboard-devin/environment/blueprint-reference)
* [Template library](/onboard-devin/environment/templates) — includes ready-to-use monorepo templates
