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

# Multi-process repository

> Use a .compose.yml project when components must be deployed together.

export const UseCaseNavigation = () => {
  useLayoutEffect(() => {
    const storageKey = "towbar-use-case-open-groups";
    const groupSelector = "#sidebar li[data-title] > button[aria-expanded]";
    let restoring = false;
    let frame = 0;
    function storedGroups() {
      try {
        return new Set(JSON.parse(sessionStorage.getItem(storageKey) || "[]"));
      } catch {
        return new Set();
      }
    }
    function save(groups) {
      try {
        sessionStorage.setItem(storageKey, JSON.stringify([...groups]));
      } catch {}
    }
    function groupName(button) {
      return button.parentElement?.dataset.title;
    }
    function rememberOpenGroups() {
      const groups = new Set();
      for (const button of document.querySelectorAll(groupSelector)) {
        if (button.getAttribute("aria-expanded") === "true") {
          const name = groupName(button);
          if (name) groups.add(name);
        }
      }
      save(groups);
    }
    function restoreOpenGroups() {
      frame = 0;
      const groups = storedGroups();
      if (!groups.size) return;
      restoring = true;
      for (const button of document.querySelectorAll(groupSelector)) {
        if (groups.has(groupName(button)) && button.getAttribute("aria-expanded") === "false") {
          button.click();
        }
      }
      restoring = false;
    }
    function scheduleRestore() {
      if (!frame) frame = requestAnimationFrame(restoreOpenGroups);
    }
    function onClick(event) {
      if (restoring || !(event.target instanceof Element)) return;
      const button = event.target.closest(groupSelector);
      if (button) {
        const name = groupName(button);
        if (!name) return;
        const groups = storedGroups();
        if (button.getAttribute("aria-expanded") === "true") groups.delete(name); else groups.add(name);
        save(groups);
        return;
      }
      if (event.target.closest('a[href^="/docs/use-cases/"]')) {
        rememberOpenGroups();
      }
    }
    const observer = new MutationObserver(scheduleRestore);
    document.addEventListener("click", onClick, true);
    observer.observe(document.getElementById("sidebar") || document.body, {
      childList: true,
      subtree: true
    });
    scheduleRestore();
    return () => {
      document.removeEventListener("click", onClick, true);
      observer.disconnect();
      cancelAnimationFrame(frame);
    };
  }, []);
  return null;
};

<UseCaseNavigation />

<img className="towbar-doc-brand-logo" src="https://mintcdn.com/avgeek/zgSzgbIpKmH9GZPv/assets/integration-logos/docker.webp?fit=max&auto=format&n=zgSzgbIpKmH9GZPv&q=85&s=53420883b82e12aab5c977f66e6391b9" alt="Multi-process repository logo" aria-hidden="true" width="709" height="512" data-path="assets/integration-logos/docker.webp" />

**Related reading:** [Compose](/docs/services/modes/compose).

The Compose file itself must be committed at the path in the manifest. This page shows Towbar's declaration, not an invented upstream Compose specification. Match the actual service name and internal port when adapting the upstream file.

## Towbar manifest

```yaml title=".towbar/services/web-worker.compose.yml" theme={"system"}
id: web-worker
name: Web and worker
file: deploy/web-worker/compose.yml
strategy: maintenance
services:
  web:
    port: 3000
    domains:
      - web-worker.example.com
    ingress:
      type: proxy
environments:
  production:
    server: 192.0.2.10
```

## Configure

1. Register and prepare the example server or servers, connect the repository, and map `production` to the branch containing these files.
2. Commit a Compose file at `deploy/web-worker/compose.yml` with the declared service name and port. Adapt it to [Towbar's Compose restrictions](/docs/services/modes/compose) before syncing.
3. Sync the repository, inspect the resolved configuration, deploy manually, and perform the verification below before enabling automation.

## Verify

Commit and validate the Compose file; no forbidden host mounts or public host ports remain.

For field constraints, see [Compose guide](/docs/services/modes/compose).
