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

# Devbox Lifecycle

> List, start, stop, and delete Devboxes, control idle auto-stop, and monitor resource usage.

export const KeepTabPosition = () => {
  useEffect(() => {
    const stateKey = "__namespaceKeepTabPosition";
    const releaseState = state => {
      state.instances -= 1;
      if (state.instances > 0) return;
      state.removeListeners();
      if (window[stateKey] === state) delete window[stateKey];
    };
    const existingState = window[stateKey];
    if (existingState) {
      existingState.instances += 1;
      return () => releaseState(existingState);
    }
    const maxSettleTime = 250;
    const requiredStableFrames = 3;
    const positionTolerance = 0.5;
    let animationFrame;
    let observer;
    let settleDeadline;
    let stableFrames = 0;
    let tabListToKeep;
    let tabListTop;
    const findTab = event => {
      if (!(event.target instanceof Element)) return null;
      return event.target.closest(".tab-container [role='tab']");
    };
    const findScrollContainer = element => {
      for (let parent = element.parentElement; parent; parent = parent.parentElement) {
        const {overflowY} = getComputedStyle(parent);
        if ((overflowY === "auto" || overflowY === "scroll") && parent.scrollHeight > parent.clientHeight) {
          return parent;
        }
      }
      return null;
    };
    const stopKeepingPosition = () => {
      if (animationFrame) cancelAnimationFrame(animationFrame);
      animationFrame = undefined;
      observer?.disconnect();
      tabListToKeep = undefined;
    };
    const restoreTabListPosition = () => {
      if (!tabListToKeep?.isConnected) return 0;
      const offset = tabListToKeep.getBoundingClientRect().top - tabListTop;
      if (Math.abs(offset) < positionTolerance) return offset;
      const scrollOptions = {
        top: offset,
        behavior: "instant"
      };
      const scrollContainer = findScrollContainer(tabListToKeep);
      if (scrollContainer) {
        scrollContainer.scrollBy(scrollOptions);
      } else {
        window.scrollBy(scrollOptions);
      }
      return offset;
    };
    const settlePosition = () => {
      const offset = restoreTabListPosition();
      stableFrames = Math.abs(offset) < positionTolerance ? stableFrames + 1 : 0;
      if (stableFrames >= requiredStableFrames || performance.now() >= settleDeadline) {
        stopKeepingPosition();
        return;
      }
      animationFrame = requestAnimationFrame(settlePosition);
    };
    observer = new MutationObserver(() => {
      stableFrames = 0;
      restoreTabListPosition();
    });
    const keepTabListInPlace = tab => {
      stopKeepingPosition();
      tabListToKeep = tab.closest("[role='tablist']");
      if (!tabListToKeep) return;
      tabListTop = tabListToKeep.getBoundingClientRect().top;
      settleDeadline = performance.now() + maxSettleTime;
      stableFrames = 0;
      observer.observe(document.getElementById("content") ?? document.documentElement, {
        attributes: true,
        attributeFilter: ["aria-selected", "class"],
        childList: true,
        subtree: true
      });
      animationFrame = requestAnimationFrame(settlePosition);
    };
    const selectWithoutNavigation = event => {
      if (!event.isTrusted) return;
      const tab = findTab(event);
      if (!tab) return;
      keepTabListInPlace(tab);
      event.preventDefault();
      event.stopPropagation();
      tab.click();
      restoreTabListPosition();
    };
    const selectWithKeyboard = event => {
      if (!event.isTrusted) return;
      const tab = findTab(event);
      const tabList = tab?.closest("[role='tablist']");
      if (!tab || !tabList) return;
      const tabs = Array.from(tabList.querySelectorAll(":scope > [role='tab']"));
      const currentIndex = tabs.indexOf(tab);
      let nextIndex;
      switch (event.key) {
        case "ArrowLeft":
          nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;
          break;
        case "ArrowRight":
          nextIndex = (currentIndex + 1) % tabs.length;
          break;
        case "Home":
          nextIndex = 0;
          break;
        case "End":
          nextIndex = tabs.length - 1;
          break;
        case "Enter":
        case " ":
          nextIndex = currentIndex;
          break;
        default:
          return;
      }
      keepTabListInPlace(tab);
      event.preventDefault();
      event.stopPropagation();
      tabs[nextIndex]?.click();
      tabs[nextIndex]?.focus({
        preventScroll: true
      });
      restoreTabListPosition();
    };
    document.addEventListener("click", selectWithoutNavigation, true);
    document.addEventListener("keydown", selectWithKeyboard, true);
    const state = {
      instances: 1,
      removeListeners: () => {
        stopKeepingPosition();
        document.removeEventListener("click", selectWithoutNavigation, true);
        document.removeEventListener("keydown", selectWithKeyboard, true);
      }
    };
    window[stateKey] = state;
    return () => releaseState(state);
  }, []);
  return null;
};

export const CenteredImage = ({src, alt, width, caption, className}) => {
  const [basePath, setBasePath] = useState("");
  useEffect(() => {
    const path = window.location.pathname;
    setBasePath(path === "/docs" || path.startsWith("/docs/") ? "/docs" : "");
  }, []);
  return <Frame caption={caption} className={className} style={{
    maxWidth: width,
    marginInline: "auto"
  }}>
			<OptimizedImage src={`${basePath}${src}`} alt={alt} />
		</Frame>;
};

<KeepTabPosition />

A Devbox exists until you delete it. In between it starts when you connect, stops when it goes idle, and keeps its persistent storage across both.

## Listing Devboxes

See which Devboxes exist and what state they are in.

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    devbox list
    ```

    This shows only your Devboxes. See [`devbox list`](/docs/reference/devbox-cli/list) for JSON output and for including other members' Devboxes.
  </Tab>

  <Tab title="TS SDK">
    ```typescript theme={null}
    const page = await client.devboxes.list({
      limit: 20,
      orderBy: "last-used",
    });

    page.items.forEach((devbox) => console.log(devbox.info));
    ```

    Listing skips per-Devbox runtime lookups, so each handle reports `info.state` as `"unknown"`. Call `refresh()` on a handle before relying on its state. Use `devboxes.iterate()` to walk every page automatically.
  </Tab>

  <Tab title="Dashboard">
    The [Devboxes page](https://cloud.namespace.so/workspace/devboxes) groups Devboxes into **My Devboxes**, **Shared Devboxes** from your workspace, and **Managed Agents** created by integrations. Each row shows the operating system, machine size, and how long the Devbox has been idle. A green dot marks a running Devbox.

    <CenteredImage width={700} alt="The Devboxes page listing Devboxes with their OS, size, idle time, and state" src="/docs/images/devboxes/lifecycle/devbox-lifecycle-list.webp" />
  </Tab>
</Tabs>

<h2 id="starting--stopping">
  Starting & Stopping
</h2>

Stopped Devboxes retain all persistent storage and resume in seconds.

<Tabs>
  <Tab title="CLI">
    Devboxes start automatically when you connect with `devbox ssh` or `devbox open-ide`. To stop one:

    ```bash theme={null}
    devbox shutdown
    ```

    `devbox stop` is an alias. See [`devbox shutdown`](/docs/reference/devbox-cli/shutdown) for its options.
  </Tab>

  <Tab title="TS SDK">
    ```typescript theme={null}
    await client.devboxes.start("my-devbox");
    await client.devboxes.stop("my-devbox");
    ```

    `start()` waits for the Devbox to become ready. Connection-backed operations such as commands, files, and terminals start a stopped Devbox on their own, so call `start()` explicitly only when you need to wait for readiness first.
  </Tab>

  <Tab title="Dashboard">
    A stopped Devbox shows a **Start** button. A running one shows the **Open VSCode** dropdown, and can be stopped from its `...` menu or from the Devbox detail page.

    <CenteredImage width={700} alt="The Devboxes page with the context menu open on a running Devbox, showing Stop and Delete" src="/docs/images/devboxes/lifecycle/devbox-lifecycle-stop-delete.webp" />
  </Tab>
</Tabs>

## Deleting

Deleting a Devbox permanently removes it and its persistent volume. This cannot be undone.

<Tabs>
  <Tab title="CLI">
    ```bash theme={null}
    devbox delete my-devbox
    ```

    See [`devbox delete`](/docs/reference/devbox-cli/delete) for skipping the confirmation and for its aliases.
  </Tab>

  <Tab title="TS SDK">
    ```typescript theme={null}
    await client.devboxes.delete("my-devbox");
    ```

    There is no confirmation step. Use `devbox.delete()` when you already hold a handle, and do not use that handle afterwards.
  </Tab>

  <Tab title="Dashboard">
    Open the `...` menu on a Devbox and select **Delete**.

    <CenteredImage width={700} alt="The Devboxes page with the context menu open on a Devbox, showing Delete" src="/docs/images/devboxes/lifecycle/devbox-lifecycle-stop-delete.webp" />
  </Tab>
</Tabs>

<h2 id="idleness--auto-stop">
  Idleness & Auto-Stop
</h2>

A Devbox stops on its own once it has been idle for the length of its idle timeout. Set that timeout when you create the Devbox, see [Idle Timeout](/docs/devbox/creating#idle-timeout).

### How idleness is detected

A Devbox is considered active (not idle) if any of the following are true:

* There is an active SSH connection, whether through `devbox ssh` or a native SSH client. This includes SSH connections kept open by IDEs.
* A session was created within the last 15 minutes.
* Files exist under `/.namespace/tasks`, which indicate ongoing tasks and can be created by users.<br />
  See the [long-running tasks guide](/docs/guides/devbox/long-running-tasks) to learn more.

The idle timeout countdown only applies once none of the conditions above are present.

## Next Steps

<Columns cols={3}>
  <Card title="Creating Devboxes" icon="plus" href="/docs/devbox/creating">
    Machine sizes, images, repositories, and workspace defaults.
  </Card>

  <Card title="Remote Development" icon="monitor" href="/docs/devbox/remote-development">
    SSH access and SSH config for a Devbox.
  </Card>

  <Card title="Sessions" icon="square-terminal" href="/docs/devbox/sessions">
    Persistent terminal sessions that survive disconnections.
  </Card>
</Columns>
