---
title: "Lifecycle moments and the environment"
description: "What a project's file runs, when, and what every line of it can reach for."
canonical: moments.html
navigation-title: "Lifecycle moments"
---

<a id="moments"></a>

- [Lifecycle moments](#lifecycle-moments)
- [Environment for commands](#environment-for-commands)

<a id="lifecycle-moments-and-the-environment"></a>

# Lifecycle moments and the environment

What a project's file runs, when, and what every line of it can reach for.

<a id="configuration-moments"></a>

<a id="lifecycle-moments"></a>

## Lifecycle moments

| Moment | Asked when |
| --- | --- |
| `install` | the worktree is built — `add`, `fork`, `provision` |
| `configure` | the same, and on every `worktree:config` |
| `setup` | a worktree with no data to inherit: the application is installed |
| `migrate` | data was copied in — `add`, `fork`, `sync` — or a rebuilt worktree has its own |
| `account` | somebody asks for an administrator of their own — and nothing else asks for it |
| `finish` | the last step of every one of them, and of a version switch |

`account` is the one moment no build asks for. A worktree that inherited a
database inherited the accounts in it, and nobody here knows their passwords;
this is what makes one that is known. The shipped TYPO3 profiles drop an account
of that name before creating it, because the core refuses a username that is
taken and has no command that changes an account it finds — so a second press
would fail on what the first one made.

A moment is the lines it runs, in the order they are written:

```yaml
install:
  - ./bin/write-registry-token.sh
  - inherit: profile
  - npm ci
```

`inherit: profile` is the one entry in that list which is not a line to run: it
is where the configuration this is built on does its own work. So the list above
writes a token, then installs the dependencies the shipped profile installs, then
builds the assets — and a later change to that profile reaches this project. Left
out, the moment is what stands there and no more. It is written as a task and not
as a word, so no line a project writes can be taken for it.

A line is a command, or a task written the way DDEV writes a hook task:
`exec:` for a command, `composer:` for composer. A bare string is `exec:`
and means exactly the same thing, so the long form is worth writing only for a
task that carries `optional:` — which is why most lines here have no kind in
front of them and a few do. A line holding `": "` is read as a task by YAML
before Branchery sees it, so put such a line in quotes.

Everything runs in the worktree, in the project's web container, through a
shell, so pipes, `&&` and heredocs work. A line that fails stops the
operation.

A task may add `optional: true`, and then a failure of that one line is a
warning rather than the end of the build:

```yaml
install:
  - composer: install --no-interaction
  - exec: cd Build && npm ci
    optional: true
```

An operation that went past an optional line ends in `⚠` with the reason,
and `--format=json` carries it under `warnings`. `optional:` is `true`
or `false`; anything else is refused. The shipped `typo3-core` marks its
`npm ci` this way, because a branch whose lock file predates the container's
npm cannot install it and is still usable for work on PHP.

A moment written as an empty list (`finish: []`) is a moment that does nothing,
which is how a project takes something away that the shipped configuration does.

<a id="configuration-environment"></a>

<a id="environment-for-commands"></a>

## Environment for commands

The worktree a line is running for is in its environment. This is what lets a
shipped configuration be a file rather than a class, and what a project's own
line reaches for when it has to point at something:

- **`BRANCHERY_NAME`**

  `my-fix`
- **`BRANCHERY_BRANCH`**

  the branch the worktree was made for — while it is checked out on something
  else, still that one
- **`BRANCHERY_URL`**

  `https://my-fix.blog.ddev.site/`
- **`BRANCHERY_HOST`**

  `my-fix.blog.ddev.site` — what a site is found by
- **`BRANCHERY_TLD`**

  `blog.ddev.site` — under whatever domain DDEV was given, `ddev.site`
  unless `project_tld` says otherwise
- **`BRANCHERY_HOSTS_PATTERN`**

  the same as a pattern, for a trusted-hosts setting
- **`BRANCHERY_PHP`**

  the interpreter this worktree is served with
- **`BRANCHERY_NODE`, `BRANCHERY_NPM`**

  the Node and npm this worktree builds with — the same ones a bare `node`
  or `npm` in a line reaches
- **`BRANCHERY_BIN`**

  where the project's binaries are, as `bin:` says
- **`BRANCHERY_DOCROOT`**

  what is served, as `docroot:` says
- **`BRANCHERY_DATABASE`**

  this worktree's own database
- **`BRANCHERY_DB_DRIVER`, `BRANCHERY_DB_HOST`, `BRANCHERY_DB_PORT`, `BRANCHERY_DB_USER`, `BRANCHERY_DB_PASSWORD`**

  the connection to it
- **`BRANCHERY_DB_URL`**

  the same connection as one string
- **`BRANCHERY_DB_CLIENT`**

  the client for this worktree's database, as a line to pipe a statement into:
  `echo "DELETE FROM be_users WHERE …" | $BRANCHERY_DB_CLIENT`. Both clients
  read from standard input, so a line needs no case for the two of them
- **`BRANCHERY_ADMIN_USER`, `BRANCHERY_ADMIN_PASSWORD`, `BRANCHERY_ADMIN_EMAIL`**

  the login a setup creates: the worktree's own name, the password
  `password:` names — `#Password1` where it names none — and an address
  under the worktree's own host. A development login, written down here,
  which is what keeps it from being a secret
