---
title: How to Run Commands and Open a Console in a MicroVM (public)
description: Run a single command or open an interactive shell inside a MicroVM&#39;s container using doctl or the API.
product: Microvms
url: https://docs.digitalocean.com/products/microvms/how-to/run-commands/
last_updated: "2026-10-09"
---

> **For AI agents:** The documentation index is at [https://docs.digitalocean.com/llms.txt](https://docs.digitalocean.com/llms.txt). Markdown versions of pages use the same URL with `index.html.md` in place of the HTML page (for example, append `index.html.md` to the directory path instead of opening the HTML document).

# How to Run Commands and Open a Console in a MicroVM (public)

DigitalOcean MicroVMs are lightweight virtual machines that run a container image in an isolated kernel, pause automatically when idle, and resume on the next request with memory, files, and processes intact.

You can run a single command or open an interactive console in a DigitalOcean MicroVM using `doctl` or the API. The Control Panel does not support either, and the Droplet console in the Control Panel does not connect to MicroVMs. Both run inside the MicroVM’s workload container, so they see the same filesystem, environment variables, and processes as your application.

Commands and consoles differ in the following ways:

| Aspect | Run a command | Console |
|---|---|---|
| What runs | The command you send | `/bin/sh` |
| Input | None. Standard input is closed. | Your keystrokes |
| Output | `stdout` and `stderr` as separate fields | One terminal stream |
| Result | Exit code in the response | Exit code when the shell exits |

The console needs `/bin/sh` in your image. Minimal images without a shell support running commands but not the console.

If the MicroVM is paused and auto-resume is on, running a command or opening a console resumes it, and the command or console waits until the MicroVM is running. If auto-resume is off, [resume the MicroVM](https://docs.digitalocean.com/products/microvms/how-to/pause-resume/index.html.md) first, or the request fails.

## Prerequisites

- A [personal access token](https://docs.digitalocean.com/reference/api/create-personal-access-token/index.html.md) with the `microvm:update` scope.
- For `doctl`, [`doctl`](https://docs.digitalocean.com/reference/doctl/how-to/install/index.html.md) v1.173.0 or later.

## Run a Command or Open a Console Using doctl

Run a command with `doctl compute microvm exec`. Put `--` before the command so `doctl` does not read the command’s flags as its own:

```shell
doctl compute microvm exec <your-microvm-id> -- nginx -v
```

`doctl` prints the command’s output. If the command exits non-zero, `doctl` also exits non-zero and reports the command’s exit code. To set the working directory, add `--cwd`.

The command runs directly, not through a shell. To use pipes, redirects, `&&`, or environment variables, wrap the command in `sh -c`:

```shell
doctl compute microvm exec <your-microvm-id> -- sh -c 'ls /usr/share/nginx/html | wc -l'
```

Open an interactive console with `doctl compute microvm console`. To leave the console, type `exit` or press `Ctrl+D`:

```shell
doctl compute microvm console <your-microvm-id>
```

The console needs an interactive terminal. It does not work in scripts, CI jobs, or with piped input.

## Run a Command Using the API

Send a `POST` request to `/v2/microvms/<your-microvm-id>/exec` with `argv` and an optional `cwd`. As with `doctl`, `argv` runs directly, not through a shell:

```shell
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
  -d '{"argv": ["nginx", "-v"]}' \
  "https://api.digitalocean.com/v2/microvms/<your-microvm-id>/exec"
```

The response contains `stdout`, `stderr`, and `exit_code`, plus `truncated` when the output was cut off. `stdout` and `stderr` are JSON strings, so bytes that are not valid UTF-8 are replaced. To return binary output, encode it in the command, for example with `sh -c '<your-command> | base64'`.

HTTP 200 means the command ran, even if the command itself failed. Check `exit_code` for the command’s result. The endpoint returns the following other status codes:

| Status | Meaning |
|---|---|
| 400 | The request is malformed, `argv` is missing or empty, or the body is larger than 1 MiB. |
| 401 | The token is missing or invalid. |
| 403 | The token does not have the `microvm:update` scope. |
| 404 | The MicroVM does not exist, or it belongs to another team. |
| 429 | Your team reached the limit on commands per minute or commands running at once. The message says which. |
| 502 | The command did not reach the workload, for example because the container is not running. |

## Open a Console Using the API

The console is a WebSocket at `wss://api.digitalocean.com/v2/microvms/<your-microvm-id>/console`. Send your API token in the `Authorization` header of the handshake. Browsers cannot set this header, so you cannot open the console from browser JavaScript. Set the initial terminal size with the `rows` and `cols` query parameters. The default is 24 rows by 80 columns.

This example uses [`websocat`](https://github.com/vi/websocat). The `-b` flag sends input as binary frames, which the console requires:

```shell
websocat -b -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
  "wss://api.digitalocean.com/v2/microvms/<your-microvm-id>/console?rows=24&cols=80"
```

The console uses the following WebSocket frames:

- **Client to server, binary**: Terminal input, such as keystrokes.
- **Client to server, text**: A resize, such as `{"resize":{"rows":40,"cols":120}}`. Other text is sent to the shell as input.
- **Server to client, binary**: Terminal output, with `stdout` and `stderr` combined.
- **Server to client, text**: A control message. Ignore keys you do not recognize. The control messages are:

  - `{"status":{"state":"resuming"}}`: The MicroVM was paused and is resuming. The shell starts when the MicroVM is running.
  - `{"error":{"code":"...","message":"..."}}`: The console failed to connect or start. `code` is `dial_failed`, `start_failed`, or `agent_error`.
  - `{"exit":{"code":0}}`: The shell exited with this code. The server then closes the connection normally.

The server sends a WebSocket ping every 30 seconds. Your client must keep reading from the connection so its WebSocket library answers the pings. Most libraries answer pings automatically.

Before the upgrade to WebSocket, the console returns the same 401, 403, and 404 errors as running a command, and HTTP 429 when the MicroVM already has four consoles open.

## Run Longer Tasks

A command has 60 seconds to finish. To run a longer task, start it in the background with its output redirected, then check on it with later commands:

```shell
doctl compute microvm exec <your-microvm-id> -- sh -c 'nohup <your-long-task> > /tmp/task.log 2>&1 &'
```

Redirect the output as shown. If a background process keeps the command’s output open, the command does not return until the 60-second limit.

You can also run a longer task in the console, which stays open for up to 4 hours.

For other limits on commands and consoles, see [MicroVMs Limits](https://docs.digitalocean.com/products/microvms/details/limits/index.html.md#command-and-console-limits).