Getting Started
This page takes you from nothing to a running, health-checked Postgres with its connection string loaded in your shell. Budget about five minutes.
Prerequisites
- Docker, installed and running.
ephtalks to your local Docker daemon to start containers. Confirm withdocker ps. - A shell. The non-container features (
run=services, lifecycle hooks, and shell health checks) run through the platform shell:sh -con Linux and macOS,cmd /Con Windows. Everything works natively on all three platforms; the one catch is that a command string written forsh(pipes,$VAR, POSIX tools) may need acmd-compatible form on Windows, or you can runephinside WSL. See Troubleshooting.
Install
Install the latest release binary. The script verifies a SHA-256 checksum before installing:
# Linux / macOS
curl -sSfL https://raw.githubusercontent.com/attunehq/doteph/main/scripts/install.sh | bash
# Windows (PowerShell)
irm https://raw.githubusercontent.com/attunehq/doteph/main/scripts/install.ps1 | iex
Both scripts honor EPH_REPO (an owner/repo, default attunehq/doteph) and
EPH_BASE_URL (replaces the GitHub download base entirely, with no release
tag appended after it) for installing from a fork or a mirror; eph update
honors the same two variables (see below).
Or build from a source checkout:
cargo install --path .
# or
make install
Confirm the binary is on your PATH:
eph --version
Keep it current later with the built-in updater: eph update installs the
latest release (checksum-verified, swapped in place), and eph update --check
just reports whether one exists. Details in the
Command Reference.
Write your first .eph file
In the root of a project, create a file named .eph:
[postgres]
image=postgres:16-alpine
port=5432
env.POSTGRES_USER=dev
env.POSTGRES_PASSWORD=dev
env.POSTGRES_DB=myapp
healthcheck=pg_isready -U dev
[env]
DATABASE_URL=postgres://dev:dev@localhost:${postgres.port}/myapp
Reading it line by line:
[postgres]declares a service namedpostgres.image=runs the officialpostgres:16-alpineDocker image.port=5432publishes the container’s port 5432 on a random free port on your machine, so it never collides with anything else.env.POSTGRES_*are environment variables passed into the container; here they configure the Postgres superuser and database.healthcheck=is a commandephruns repeatedly until it succeeds, soeph uponly returns once Postgres actually accepts connections.[env]opens a section for top-level variables: a plainKEY=VALUEline directly after a service section is a parse error (see The.ephFile), so anything you wanteph envto export after your services go here.DATABASE_URL=...is a top-level environment variable for your shell.${postgres.port}is replaced with the real assigned host port when you runeph env.
Comments must be on their own line, starting with
#. A#after a value is part of the value, not a comment. See The.ephFile.
Validate it
Before starting anything, check that the file parses:
eph check
This reports the environment variables and services it found, or a parse error with a line number. It never touches Docker, so it is always safe to run.
Start your services
eph up
eph pulls the image if needed, starts the container, waits for the health
check to pass, and prints the assigned port:
Services started:
postgres -> localhost:54321
Run `eval "$(eph env)"` to set environment variables
See what is running
eph status
Workspace: /home/you/projects/myapp
ID: a1b2c3d4e5f60718
Running services:
postgres -> localhost:54321
Load the connection details into your shell
eph env prints shell-ready variable assignments with the real ports filled
in:
$ eph env
export DATABASE_URL="postgres://dev:dev@localhost:54321/myapp"
Load them into your current shell:
eval "$(eph env)" # bash / zsh / sh
$DATABASE_URL points at your running Postgres, and your app can connect.
fish, PowerShell, and JSON formats are covered in
Shell Integration.
Stop your services
eph down
This stops the container but keeps it and its data, so the next eph up
is fast. To also remove the container:
eph down --rm
To wipe everything for this workspace (containers, named volumes and their data, and saved state):
eph clean
The core loop
That is the whole day-to-day workflow:
eph up # start services
eval "$(eph env)" # load connection details
# ... work ...
eph down # stop when you are done
Next
You have the mechanics. Read Core Concepts to understand why it works this way (workspaces, isolation, ports, and the lifecycle), which makes everything else in the guide fall into place.