The Command Line Tool

Indigo ships a command line tool, indigo, that does from the terminal what you would otherwise do in Indigo’s window: create, start and stop stacks, add and remove services, link a project folder as a site and change its PHP or web server, create and export databases, override a service’s configuration, find the right log file, or run a command with a stack’s own PHP and MySQL on the PATH.

The tool talks to the running app, so Indigo.app must be open. If it isn’t, every command stops with Indigo is not running.

Not the same as Shell Integration

Shell Integration puts a stack’s services on your PATH for an interactive terminal session. The command line tool controls Indigo itself. When you want a stack’s tools for a single command without switching your shell, use indigo exec.

Installing

Indigo offers to install the tool the first time it runs. You can also install or remove it at any time from Settings > Integrations > CLI Tool.

Either way, Indigo places a symlink at /usr/local/bin/indigo pointing into the app bundle, and refreshes it each time the app launches, so the tool keeps working if you move Indigo to a different folder.

To check it’s in place, open a new terminal window and ask for the version:

indigo version
Indigo CLI: 1.1.0
Indigo.app: 2.1.0

indigo --help lists every command, and indigo help <command> describes one in detail.

How commands find their stack

Most commands act on one stack. Name it with -s (or --stack), using either its label or the short UUID that indigo stack list shows. Quote a label that contains spaces.

Leave -s out, and the tool looks at your current directory. If you are inside the project folder of a linked site, that site’s stack is used. Anywhere else, the command stops with No stack specified, except link, unlink, open, stack reload and the service commands, which use your stack if you only have one.

cd ~/Sites/my-shop
indigo restart                 # the stack that serves ~/Sites/my-shop
indigo restart -s "Client work"
indigo restart -s NCDLIFE

Flags every command takes

FlagWhat it does
-s, --stack <label or UUID>Choose the stack, as above.
-f, --format jsonPrint the result as JSON instead of text. This is the mode for scripts and coding agents: output is a single document, and a failure is a JSON envelope on stdout with a code, a message and suggestions, alongside a non-zero exit code.
-y, --yesSkip the confirmation prompt on the commands that ask one (link, unlink, stack delete, service remove, db drop, config override delete). Scripts need this, or they hang waiting for an answer.
--no-waitFor the commands that start, stop or restart a stack (start, stop, restart, stack rebuild, stack reload, stack delete, service set, service remove): return as soon as the request is accepted instead of waiting for the stack to finish.
--timeout <seconds>How long those commands wait before giving up. The default is 300.
-q, --quietSuppress progress lines, leaving only the result.
-v, --verboseShow what the tool is doing, for diagnosing a command that misbehaves.

Stacks

indigo stack list shows every stack with its UUID, whether it’s running, and how many services it holds. Add --running or --stopped to see only one or the other.

indigo stack list
NAME                  UUID      STATUS      SERVICES
My Drupal Site        NCDLIFE   running     5
Client work           40EB2F    stopped     6

indigo stack info describes one stack: its label and UUID, where its configuration bundle and compiled files live, each service with its version, status and ports, and the sites it serves, with a note against any that has a problem.

indigo stack info -s "My Drupal Site"

indigo stack start, stop and restart do what they say and wait until the stack gets there. indigo stack rebuild rebuilds every service in the stack from scratch, then starts it again. The three everyday ones also work without the stack word: indigo start, indigo stop and indigo restart.

indigo start -s "My Drupal Site"
indigo stack rebuild -s "My Drupal Site" --no-wait

Creating and deleting stacks

indigo stack create makes a new stack from a name and the services you want in it. Its bundle goes into ~/Documents/Indigo, as the New Stack wizard’s does, unless you give --path. Nothing is built or started until you indigo start it.

indigo stack create --label "New Project" --service [email protected] --service [email protected] --service nginx
indigo start -s "New Project"

If you already have a stack bundle (one you wrote by hand, say, or one checked into the project), --from-config adds it to Indigo where it is, exactly as double-clicking it would. The bundle stays the stack’s home, so later edits to it are edits to the stack.

indigo stack create --from-config ~/Sites/my-shop/my-shop.indigostack

indigo stack delete stops a stack, removes it from Indigo and moves its bundle and its built services to the Trash, as deleting it from the sidebar does. Name the stack explicitly: delete never guesses from your current directory.

indigo stack delete "Old Project" --yes

Editing a stack’s config by hand

A stack’s settings live in config.json inside its .indigostack bundle, and you or your coding agent can edit that file directly. Indigo keeps each stack in memory, though, so tell it to look again with indigo stack reload. A running stack restarts on the new settings.

indigo stack reload -s "My Drupal Site"

Until you reload, Indigo refuses to start, restart or change that stack, rather than quietly saving its old copy over your edit. indigo stack info warns about it too.

Services

indigo service list shows the services in a stack with their versions, status and ports. A port marked (auto) is one Indigo picks afresh each time the stack starts.

indigo service list -s "My Drupal Site"

indigo service add adds a service, given as type@version. A bare type is enough when Indigo ships only one version of it. A running stack carries on without the new service until you restart it.

indigo service add [email protected] -s "My Drupal Site"
indigo service add redis -s "My Drupal Site"
indigo restart -s "My Drupal Site"

indigo service remove takes one out. It refuses, and says why, while a web server still hosts sites or a site still links to the PHP, and while a database server still holds databases, unless you add --delete-data, which moves its data to the Trash rather than erasing it. A running stack is stopped first and left stopped.

indigo service remove [email protected] -s "My Drupal Site" --yes
indigo service remove mariadb -s "My Drupal Site" --yes --delete-data

You can name a service by its type (php), type@version ([email protected]), its nickname, or its ID from indigo service list.

Changing a service’s port

indigo service set changes the port a database server, Redis or PHP listens on, or Mailpit’s SMTP and web ports (--smtp-port, --http-port). Give a number from 1024 to 65535, or auto to let Indigo pick a free one each start. A running stack restarts to apply it.

indigo service set mariadb --port 3306 -s "My Drupal Site"
indigo service set mailpit --smtp-port 2525 -s "My Drupal Site"

A port something else already has is refused, naming whatever has it. So to hand one service’s port to another, move the first one out of the way, then give the port to the second. That’s the whole trick to moving a project from MySQL to MariaDB without touching its connection settings: add MariaDB, copy the data across, then swap the ports. Here MySQL is on 3306, and indigo service list gave the two servers’ IDs:

indigo service add [email protected] -s "My Shop" && indigo restart -s "My Shop"
indigo db export -s "My Shop" --service mysql_8D68 shop_db -o shop_db.sql
indigo db create -s "My Shop" --service mariadb_B73D shop_db
indigo db import -s "My Shop" --service mariadb_B73D shop_db shop_db.sql
indigo service set mysql --port 3307 -s "My Shop"     # MySQL steps aside
indigo service set mariadb --port 3306 -s "My Shop"   # MariaDB takes its old port

indigo link turns the current directory into a site. Indigo looks at the folder, works out which framework it holds, and proposes a domain based on the folder name, the right document root, and the PHP version and web server that suit it, preferring ones the stack already has. Choose a different domain with -d (or --domain), and a different PHP or web server with --php and --server.

If the framework needs a service the stack doesn’t have, link lists it and asks whether to add it. With --yes it doesn’t add services on its own say-so: it stops with the list, and you add them by passing --add-missing-services as well.

If you have one stack, link uses it. With more than one, say which with -s.

cd ~/Sites/my-shop
indigo link -s "Client work" --domain shop.test
Detected: Laravel
Domain: shop.test
Document root: /Users/you/Sites/my-shop/public

Proceed? [Y/n] y

✓ Created site shop.test

URL: https://shop.test
indigo link -s "Client work" --php 8.3 --server apache --yes

indigo unlink removes the site linked to the current directory, after asking you to confirm. From anywhere else, name the site with --domain. The project files stay where they are.

indigo site edit changes a site after the fact: its PHP version, its web server, its document or project root, or its domain. The PHP version or web server must already be in the stack (indigo service add first). A running stack restarts to apply the change.

cd ~/Sites/my-shop
indigo site edit --php 8.4
indigo site edit -s "Client work" --domain shop.test --server nginx
indigo site edit --domain shop.test --new-domain myshop.test

indigo open opens the current directory’s site in your browser. Given -s instead, it opens the stack’s first site. indigo open --service mailpit opens Mailpit’s inbox instead.

Databases

indigo db list shows the databases in a stack’s database services, with table counts and sizes for MySQL and MariaDB, and key counts for Redis.

indigo db list -s "My Drupal Site"
mysql:
  • drupal_db (112 tables, 48.3 MB)
  • drupal_db_test (0 tables, Zero KB)
redis:
  • Redis (4 keys)

indigo db create <name> creates a database in the stack’s first database service. indigo db drop <name> deletes one, after asking you to confirm.

indigo db export <name> writes <name>.sql into the current directory. Choose another path with -o (or --output), and add --gzip to compress it. With --gzip, Indigo appends .gz to whatever path you gave. indigo db import <name> <file> loads an SQL file into the named database.

indigo db export -s "My Drupal Site" drupal_db --gzip -o ~/Desktop/drupal_db.sql
indigo db import -s "My Drupal Site" drupal_db_test ~/Desktop/fixtures.sql
indigo db drop -s "My Drupal Site" drupal_db_test --yes

When a stack has more than one database service, tell the db commands which one with --service, giving the service’s ID as indigo stack info shows it (for example mysql_8947, or just 8947).

Configuration overrides

Indigo regenerates each service’s configuration from templates every time the stack starts, so editing the running configuration doesn’t last. An override is a copy of one of those files kept in the stack’s configuration bundle. Indigo lays overrides over the generated files at startup, so your change survives restarts and travels with the stack.

indigo config override paths --service <service> shows the three directories involved: the clean templates to copy from, the compiled directory the service actually reads (don’t edit it), and the overrides directory where your copies go.

indigo config override create --service <service> <file> makes an override for one file, copying it from the template so that its {{variables}} are preserved. Give the path relative to the service’s directory, as paths shows it. Edit the new file, then restart the stack.

indigo config override list --service <service> lists the overrides in place, and indigo config override delete --service <service> <file> removes one, after asking you to confirm, so the service goes back to its default on the next restart.

indigo config override create -s "My Drupal Site" --service php etc/conf.d/custom.ini
indigo config override list -s "My Drupal Site" --service php
indigo restart -s "My Drupal Site"

Here --service accepts a service type such as php or mysql, or the service’s ID from indigo stack info.

For PHP directives alone, the Configuration overrides field on the PHP service in Indigo’s window does the same job without touching files. See Configuring PHP.

Logs

indigo logs prints the path of every log file a stack writes: each service’s own logs, and the access and error log of each site. A file the service hasn’t created yet is marked (not found). Narrow it to one service with --service.

The tool doesn’t show the log contents. Hand the path to whatever you prefer:

indigo logs -s "My Drupal Site"
tail -f ~/.indigo/stacks/NCDLIFE/nginx_9F1D/logs/mysite.test-error.log

In JSON, the paths are keyed by service ID and by site domain, which is convenient in a script:

tail -f "$(indigo logs -s "My Drupal Site" --format json | jq -r '.sites["mysite.test"].error')"

Running a command in a stack’s environment

indigo exec runs a command with a stack’s environment: the stack’s own PHP, MySQL or MariaDB, Redis and Node on the PATH, each command-line client already pointed at its service’s port. Everything after -- is the command. Its output and exit code are passed straight through, which makes exec the tool for npm scripts, Makefiles, CI steps and coding agents that need a stack’s tools without an interactive shell.

indigo exec -- php artisan migrate
indigo exec -s "My Drupal Site" -- composer install
indigo exec -s "My Drupal Site" -- mysql -e "SHOW DATABASES"

The stack needs to have been started at least once, so that its environment exists. If it hasn’t, exec says so and suggests indigo stack rebuild.

Health and version

indigo health reports whether Indigo is up, its version, and whether it’s busy (showing a dialog, say) and holding other requests until it’s free. indigo version prints the versions of the tool and the app.

indigo health --format json
{
  "busy" : false,
  "status" : "healthy",
  "version" : "2.0.0"
}

Using the tool from scripts and coding agents

Three habits make the tool dependable in anything that runs unattended:

  1. Pass --format json and read the output with jq or your language’s JSON parser. Text output is for people, and its wording may change.
  2. Pass --yes to any command that would otherwise prompt.
  3. Check the exit code. A failed command exits non-zero, and under --format json prints an error envelope you can act on, for example STACK_NOT_FOUND with the name it couldn’t match.

If Indigo takes too long to answer a command that changes something, the tool doesn’t send it again, because the change may already be under way. It says so instead: check with indigo stack info before trying again.

if indigo stack info -s "My Drupal Site" --format json | jq -e '.status == "running"' > /dev/null; then
  indigo exec -s "My Drupal Site" -- php artisan test
fi