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

# route

> Create Instance-targeted app Routes and Node-owned custom proxy Routes, change Route targets, domains, or publication intent, and remove Routes.

A Route is a domain that reaches an Instance or a Node-local service. Orbit creates a Project Route for every Instance of a web-serving Project. The `route` family creates explicit Project Routes and custom proxy Routes, changes their targets, domains, and publication, and removes them.

The [Routes reference](/docs/reference/routes) describes the Route record, domain selection, traffic setup, and the rules that refuse a change while an active Instance depends on a Route.

## Commands

| Command | Result |
| - | - |
| [`route:create`](#orbit-routecreate) | Create an explicit app Route for an Instance or a Node-owned custom proxy Route. |
| [`route:list`](#orbit-routelist) | List Routes. |
| [`route:show`](#orbit-routeshow) | Show one Route. |
| [`route:update`](#orbit-routeupdate) | Change the domain, publication, or web root of a Project Route. |
| [`route:target:set`](#orbit-routetargetset) | Set the target, or a complete production target set. |
| [`route:target:unset`](#orbit-routetargetunset) | Clear the target. |
| [`route:destroy`](#orbit-routedestroy) | Remove a Route. |

Every command accepts `--json`. Route, Project, Instance, and Cluster arguments are numeric IDs. Human lists show a table with every target of a pool. `route:show` shows a detail tree with identity, scope, targets, publication, lifecycle, and replacement fields. Requests show progress while they wait.

## orbit route:create

Create an explicit app Route targeting an Instance, or create a custom proxy Route for a Node-local service.

```bash theme={"dark"}
orbit route:create <instance> <domain> [--publication=private|public] [--web-root=PATH]
orbit route:create <domain> --node=NODE --upstream=URL
orbit route:create <domain> --node=NODE --process=PROCESS
```

| Argument | Required | Meaning |
| - | - | - |
| `instance` | App form | Numeric Instance ID. Its Project owns the Route; its Node or active Cluster determines the scope. |
| `domain` | yes | The Route domain. The Gateway normalizes it. |

| Option | Default | Meaning |
| - | - | - |
| `--publication=INTENT` | `private` | `private` or `public` for the app form. Custom proxy Routes are private only. |
| `--node=NODE` | none | Serving Node ID or name, required only for the custom proxy form. |
| `--upstream=URL` | none | Loopback HTTP URL for a custom proxy Route, such as `http://127.0.0.1:4788`. |
| `--process=PROCESS` | none | Name or ID of a Node Process on the serving Node, for a custom proxy Route. |
| `--web-root=PATH` | none | A web root inside the Instance's checkout or release, such as `apps/docs/public`. The Route becomes another site of the Instance. A production Instance needs a deployed release. |

```bash theme={"dark"}
orbit route:create 12 shop.example.test
orbit route:create 12 shop.example.com --publication=public
orbit route:create 12 docs.shop.test --web-root=apps/docs/public
orbit route:create executor.orbit --node=beast --upstream=http://127.0.0.1:4788
orbit route:create executor.orbit --node=beast --process=executor
```

In a terminal, Orbit lists available Instances for an omitted Instance ID and prompts for an omitted domain. If no Instances are available or selection is cancelled, it creates nothing. In noninteractive or JSON mode, provide both arguments for the app form.

The app form creates and activates a Route for the Instance. The Instance implies the Project and scope. An inactive Instance returns `route.target_inactive`; an Instance already targeted by another Route returns `route.target_conflict`. An identical retry for an existing active Route returns that Route. With `--web-root`, the Instance keeps its own Route and gets another site. See [Create and change targets](/docs/reference/routes#create-and-change-targets) and [Serve several web roots](/docs/reference/routes#serve-several-web-roots).

`--upstream` or `--process` selects the custom proxy form. Its first argument is the domain, and it needs `--node`. It cannot take an Instance or public publication. A successful custom proxy request converges its Node-local serving path.

| Error code | Meaning |
| - | - |
| `route.domain_invalid` | The domain is not a valid domain. |
| `route.domain_conflict` | Another Route owns the domain, or it is a reserved name: `gateway.orbit`, `metrics.orbit`, `reverb.orbit`, `analytics.orbit`, or `collector.cli-proxy-api.orbit`. |
| `route.retry_conflict` | A Route with this domain exists with a different Instance, publication, or custom proxy configuration. |
| `route.scope_required` | A custom proxy Route needs a serving Node and uses the domain as its only positional argument. |
| `route.target_inactive` | The Instance is not active. |
| `route.target_web_root_unsupported` | The target Instance has no supported relative web root, such as a package rooted at `.`. |
| `route.target_conflict` | The target Instance already has a Route without a web root. |
| `route.web_root_release_missing` | The production Instance has no selected release. Deploy it first. |
| `route.web_root_unsafe` | The production web root would serve an application `.env`, or sits in the default directory without being the Instance root. |
| `app-prod.web_root_invalid` | The selected production release lacks the web root or its application directory, or the web root holds a link. |
| `route.web_root_unsupported` | A custom proxy Route got a web root. |
| `route.router_required` | The Cluster has no active Router. |
| `route.node_inactive`, `route.cluster_inactive` | The Instance's Node or Cluster, or the custom proxy's Node, is not active. |
| `route.upstream_invalid` | The upstream is not a loopback HTTP URL. |
| `route.upstream_unresolved` | The Process has no single Node-local listener. |
| `route.process_conflict` | The Process is not a Node Process on the serving Node. |

## orbit route:list

List the Routes on the Nodes you may address, with domain, kind (`app`, `custom_proxy`, or `analytics_tracking`), provenance, publication, scope, target or upstream, and status.

```bash theme={"dark"}
orbit route:list [--json]
```

## orbit route:show

Show one Route with its kind, generation basis, upstream or Process, lifecycle, and the failure fields of an unfinished change.

```bash theme={"dark"}
orbit route:show <route>
```

## orbit route:update

Change the domain or the publication of an explicit Project Route, or the web root of a Route. Give at least one option. Send `--web-root` on its own.

```bash theme={"dark"}
orbit route:update <route> [--domain=DOMAIN] [--publication=INTENT] [--web-root=PATH]
```

| Option | Meaning |
| - | - |
| `--domain=DOMAIN` | The new domain. |
| `--publication=INTENT` | The new publication, `private` or `public`. |
| `--web-root=PATH` | The new web root. `--web-root=` clears it, so the Route serves the Instance's effective root. |

```bash theme={"dark"}
orbit route:update 9 --domain=shop.example.com
orbit route:update 9 --publication=public
orbit route:update 14 --web-root=apps/admin/public
```

A domain change creates a replacement Route and returns its ID. The current Route stays authoritative until cutover. A publication-only change keeps the Route ID. See [Change an explicit domain](/docs/reference/routes#change-an-explicit-domain) and [Publish the public edge](/docs/reference/routes#publish-the-public-edge).

<Note>
  During a domain change, `route:show` shows both Routes, `replacement_step`, `failed_step`, and `error_code`. Repeat the same request to resume. A different domain or publication request changes nothing.
</Note>

| Error code | Meaning |
| - | - |
| `route.update_required` | No option was given. |
| `route.kind_unsupported` | The Route is a custom proxy or analytics tracking Route. |
| `route.domain_immutable` | The Route is generated. Only an explicit domain can change. |
| `route.domain_conflict` | Another Route owns the new domain. |
| `route.domain_change_conflict` | Another domain change is in progress. |
| `route.web_root_domain_immutable` | A Route with a web root keeps its domain. Create a new Route and remove the old one. |
| `route.web_root_update_separate` | `--web-root` was combined with another option. |
| `route.web_root_unsupported` | The Route is not an active app Route with one active target. |
| `route.web_root_conflict` | The Route is the only Route without a web root of a `laravel-app` or `symfony-app` Instance, or of a production Instance. |
| `route.target_conflict` | A cleared web root would give the Instance a second Route without a web root. |
| `route.reconciliation_required` | The Route or its targets do not allow this change, for example a public domain for development Instances. |
| `instance.source_profile_missing` | A target has no recorded source profile. Orbit does not recover missing profiles on older Instances; see the [no-legacy-support rule](/docs/reference/projects#one-public-name-without-compatibility). |

## orbit route:target:set

Set the Instance target, or send a complete production target set.

```bash theme={"dark"}
orbit route:target:set <route> <target> [--targets=ID]... [--reassign=ID:ROUTE]... [--remove=ID]...
```

| Argument | Required | Meaning |
| - | - | - |
| `route` | yes | Numeric Route ID. |
| `target` | yes | Numeric Instance ID, or the first ID of a production target set. |

| Option | Meaning |
| - | - |
| `--targets=ID` | The next Instance ID of the ordered target set. Repeat it for each ID. |
| `--reassign=ID:ROUTE` | A detached Instance ID and its destination Route ID. Repeat it for each Instance. |
| `--remove=ID` | A detached Instance ID that you allow Orbit to remove. Repeat it for each Instance. |

```bash theme={"dark"}
orbit route:target:set 9 12
orbit route:target:set 9 12 --targets=15 --reassign=18:4 --remove=19
```

Without pool options, the command sets one target. With them, it sends the complete target set and a disposition for each detached Instance. [Change a production target set](/docs/reference/routes#change-a-production-target-set) lists the rules and error codes. A single-target request that would take an Instance from another Route, or detach an active Instance from its only Route, returns `route.target_conflict` and changes nothing. A production target set can take an Instance from another Route in the same Cluster.

## orbit route:target:unset

Clear the target and keep the Route, its domain, scope, and publication.

```bash theme={"dark"}
orbit route:target:unset <route> [--yes]
```

Clearing an empty Route returns it unchanged. The Gateway returns `route.target_conflict` when clearing would leave an active Instance without a Route. On a [replacement that never activated](/docs/reference/routes#remove-a-replacement-that-never-activated), it returns `route.target_conflict` and names `route:destroy`.

## orbit route:destroy

Remove a Route and its DNS records, Caddy sites, certificates, and firewall rules. For a Route whose Instances are not active, also withdraw the PHP-FPM pools of its development Instances. See [Remove a Route](/docs/reference/routes#remove-a-route). On a `pending` or `failed` replacement Route that never activated, it abandons the domain change and keeps the Route it would replace. See [Remove a replacement that never activated](/docs/reference/routes#remove-a-replacement-that-never-activated).

```bash theme={"dark"}
orbit route:destroy <route> [--yes] [--offline] [--json]
```

| Option | Meaning |
| - | - |
| `--yes` | Confirm removal without prompting. |
| `--offline` | Remove the Route without changing a Node the Gateway cannot reach. The Gateway probes each Node first, and a Node that answers keeps every step. |
| `--json` | Return machine-readable JSON. |

When a Node the removal changes does not answer, the Gateway returns `route.node_unreachable`. The message names the Node and `--offline`. With `--offline`, the response lists each skipped Node and its remaining steps under `retained_on_nodes`. Run `orbit node:converge NODE` once that Node answers. See [Remove a Route from an unreachable Node](/docs/reference/routes#remove-a-route-from-an-unreachable-node).

<Warning>
  The Gateway refuses removal with `route.target_conflict` while an active Instance depends on the Route. A replacement that never activated is the exception, because its Instance keeps the Route it replaces. Remove the Instance with `instance:destroy` instead. That removal deletes the Route when it removes the last target. The Gateway also refuses direct removal of analytics tracking Routes with `route.tracking_managed`; disable analytics on the Instance instead. A Route kind that cannot be destroyed returns `route.kind_invalid`.
</Warning>

`route:destroy` and `route:target:unset` resolve the Route and then ask for confirmation, with No selected. Pass `--yes` for automation, also with `--json`. Declining, Ctrl-C, or end of input returns `input.cancelled` and sends nothing. A call without a terminal and without `--yes` returns `input.confirmation_required`.

## Related

* [`instance`](/docs/cli/instance) creates the Instances that Project Routes target, and accepts `--domain` for an explicit Route.
* [`process`](/docs/cli/process) creates the Node Process that a custom proxy Route can target.
* [`cluster`](/docs/cli/cluster) sets the Router that serves Cluster-scoped Routes.
* [`dns`](/docs/cli/dns) points a TLD or a Route name at an address on a Mac.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.