> ## 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.

# Internal Metabase

> Metabase and its PostgreSQL application database in one adapted Compose project.

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/EGkEWLTQnOwecqNx/assets/use-case-logos/metabase.svg?fit=max&auto=format&n=EGkEWLTQnOwecqNx&q=85&s=6c66e59085431994cb8ddea9829ad930" alt="Internal Metabase logo" aria-hidden="true" width="24" height="24" data-path="assets/use-case-logos/metabase.svg" />

**Related reading:** [Metabase upstream](https://www.metabase.com/docs/latest/installation-and-operation/running-metabase-on-docker).

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/metabase.compose.yml" theme={"system"}
id: metabase
name: Internal Metabase
file: deploy/metabase/compose.yml
strategy: maintenance
services:
  metabase:
    port: 3000
    domains:
      - metabase.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/metabase/compose.yml` with the declared service name and port. Adapt it to [Towbar's Compose restrictions](/docs/services/modes/compose) before syncing.
3. Use the upstream PostgreSQL Compose configuration in the same project and set Metabase's application-database variables there. The Towbar Compose manifest does not create or connect a separate managed Datastore.
4. Sync the repository, inspect the resolved configuration, deploy manually, and perform the verification below before enabling automation.

## Verify

Configure Metabase's application database per upstream guidance.

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