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

# Connect a frontend to a backend

> How a frontend reaches its backend, how a backend reaches its worker, and how everything else reaches the org's shared instance

Most apps are more than one service, and each service expects to find the
others at a fixed `localhost` port. Tesserc keeps that arrangement on the box.
A dependency is a loopback port declared in the manifest, and Tesserc connects
that port to the right instance of the other service, wherever it is
actually running.

```toml theme={"theme":"css-variables"}
# .claude/skills/devboxes/web.toml
ports = [3000]

[run]
setup = "pnpm install"
dev   = "pnpm dev"

[deps]
5001 = "api"      # localhost:5001 on the web box reaches api
5432 = "db"       # any TCP service, so a database works too
```

The app keeps its existing `API_URL=http://localhost:5001` and nothing in it
needs to change.

## Which instance a dependency reaches

A dependency names a service, not a box. The rule has no special cases: a
dependency reaches the box you wired it to, otherwise the org's shared
instance of that service (described below), and
otherwise nothing. `dev` starts the server anyway and says nothing about
it; connections to the port fail, and on the laptop the request gets a 503
naming the `tesser wire` command that would fix it. `tesser service ls`
shows which services have a shared instance before you start.

Nothing is ever wired automatically. Two boxes only talk to each other
because someone pointed one at the other:

```sh theme={"theme":"css-variables"}
API=$(tesser dev api)
WEB=$(tesser dev web)
tesser wire "$WEB" api "$API"
```

This works the same whether the two services live in one repository or two:
a wire connects boxes, and it does not matter which worktree they came from.

A shared instance's dependencies never resolve to anyone's dev box, so work in
progress on one person's branch cannot affect a teammate.

## Reaching a box by name

A wire is for code that expects a fixed `localhost` port. Code that is happy
to name the box can skip the wire entirely: on any of your boxes,
`http://box-<id>.localhost:<port>` reaches that box's declared port, the
same address the laptop uses. This is a convenience for scripts and
one-off checks, not a substitute for a dependency, and a port the target does
not declare in its manifest is refused. Every instance box in the org has one,
the shared instances included: a shared instance can dial a dev box that
handed it its address, which is how a dev box registers for webhooks. That is
separate from what a dependency resolves to, described above: a shared
instance's own deps still never reach anyone's dev box. See
[localhost](https://tesser.sh/docs/localhost.md#every-box-has-an-address).

## The shared instance

A shared instance runs one service at one specific commit, with no laptop
involved. It is what everyone's boxes use for the services they are not
currently working on.

```sh theme={"theme":"css-variables"}
tesser make api --ensure-running $(git rev-parse origin/main)
```

This creates a box, checks out that commit on it, runs `setup` and `dev`,
waits for the health check to pass, and makes the box the org's shared instance of
`api`. Running the command again with the same commit does nothing and prints
the same box id. Running it with a new commit starts a new box, waits until
the new box is healthy, switches the shared instance over, and then removes the
old box. To roll back, run it again with the previous commit.

Usually CI runs this for each service on every push to main. The box belongs
to the org rather than to a person, so it cannot be synced to, and its env
values come from `tesser env set` rather than from a file (see
[Services](https://tesser.sh/docs/services.md#secrets-for-shared-instances)).

`dev` starts only the requested service. It wakes the dependencies you own
and the shared instances it depends on, and once its own dev server is ready
it waits for them to serve, printing which ones it is waiting on. If a
dependency is removed, its dev server exits, it is still asleep after 15
seconds, or it does not come up in time, `dev` reports that the dependency is
not serving and finishes anyway; `tesser status <box_id>` shows where that box
is. `dev` does not create missing dependencies: use `ensure-running` to create
missing shared instances.

## Wiring a dependency

```sh theme={"theme":"css-variables"}
tesser wire <box_id> api <other_box_id>
tesser wire <box_id> api --shared
tesser wire <box_id>
```

The first command points one box's `api` dependency at a box you choose: your
own dev box of `api`, a teammate's box, or an older build. `--shared` returns
it to the org's shared instance, and the bare form shows where every
dependency of the box currently points. `tesser wire` refuses a target that
is not a box in your org, has been removed, or runs a different service than
the dependency names. After saving a wire, it waits until this laptop's
daemon routes the change before it returns. If the daemon has not loaded the
wire after 70 seconds, the command fails; the wire stays saved, and
`tesser daemon stop` followed by `tesser use` restarts the daemon. The panel lists the branches
serving the current port, marks the current one `custom wiring` when a
laptop port reaches a different box than the box's own dependency on that
port does, and names any route that is failing;
`tesser use --json` prints the full dependency graph and the laptop routes.
Laptop selection can override individual subtrees without changing these wires.

A wire names a box, and it stays put: if the target box is later removed, the
dependency fails loud rather than silently falling back to the shared
instance. Re-wire it, or return it to `--shared`.

To see a backend change through a frontend you are not working on, run that
frontend yourself from a worktree at `main` and wire it back at your box:

```sh theme={"theme":"css-variables"}
API=$(tesser dev api)                     # your change, in the backend repo
git -C ../frontend worktree add /tmp/web-backend-B origin/main
WEB=$(cd /tmp/web-backend-B && tesser dev web)
tesser wire "$WEB" api "$API"
```

The shared instance stays untouched; the copy showing your branch's data is
yours alone. Use a separate frontend worktree for each simultaneous backend
test setup: `tesser dev` reuses the box for a worktree and service. In a
monorepo, run the dashboard service from the backend change's worktree.

When both dashboard and backend depend on hp, wire both to the hp instance
intended for the test. Selecting the dashboard brings all reachable services
to localhost, but does not repair inconsistent remote wiring. The agent
prepares and verifies the graph; the panel selects it.

## Tests that need the dependencies

A workbench has no dependencies of its own, because it does not serve
anything. For an integration test that expects `localhost:5432` to be a
database, borrow a service's dependencies for the run:

```sh theme={"theme":"css-variables"}
tesser exec --deps-of api -- pnpm test:integration
```

The workbench gets `api`'s dependency ports for as long as the command runs
and releases them afterwards. The ports resolve exactly as they do for
`api`'s own box in this worktree, its wires included, so the test sees
what the service sees. `--in api` on its own only changes the working
directory to `api`'s `root`.

## Names

Service names are shared across the org. `api` means the same service whether
the manifest lives in this repository or another one, which is what lets a
dependency declared in one repository reach a service declared in another.
Registering a name that another repository already owns is an error.


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