Skip to content

Install

Caravel ships as a container image and a compose file, so the whole install is one command and a browser. Everything below assumes Docker or Podman and nothing else — no Go toolchain, no database to set up by hand.

With Docker Compose

git clone https://github.com/lkiesow/caravel.git
cd caravel
docker compose up -d

Then open http://localhost:8080. What to do there is First run.

Podman works the same way (podman compose up -d).

SQLite or Postgres

docker-compose.yml runs Caravel on SQLite, which is the right default: one household planning trips together is nowhere near what SQLite can take, and it means one fewer container to run and back up.

Use the other file if you already run Postgres and would rather have Caravel in it:

docker compose -f docker-compose.postgres.yml up -d

That file brings up a postgres:17-alpine alongside the app and waits for it to be healthy before starting.

There is no migration path between the two dialects

Caravel can create its schema in either, but nothing moves data from one to the other. Pick one before you put real trips in it.

Where the data lives

Two volumes, and they belong together:

Path in the container Holds
/data The SQLite database (caravel.db), when running on SQLite
/uploads Every uploaded photo and document

Uploads are files on disk, not blobs in the database, so a backup of one without the other restores to a database full of references to pictures that no longer exist. See Backup and restore.

Configuring it

Everything is set through environment variables, and every one has a working default — a bare docker compose up -d is a complete installation. The compose files read an optional .env beside them, which is where a real deployment puts its settings. The checkout ships an annotated .env.sample listing every variable, commented out at its default:

cp .env.sample .env
$EDITOR .env
docker compose up -d

.env is gitignored; .env.sample holds no values, so it is safe to keep in the repository and safe to diff against after an upgrade. See Server and database for the full list. Two things are worth turning on once it is running: an address search endpoint of your own, and optionally the assistant.

From an RPM

For Fedora, RHEL and anything else RPM-based, each release carries a package for x86_64 and aarch64:

sudo dnf install ./caravel-1.0.0-1.el10.x86_64.rpm
sudo systemctl enable --now caravel

That is a complete installation. The package creates a caravel system user, installs a systemd unit, and puts the database and uploads in /var/lib/caravel. Configuration is /etc/caravel/caravel.conf, which is marked noreplace — an upgrade will not overwrite your edits.

sudo systemctl status caravel
curl http://localhost:8080/api/health

There is no repository to add, so upgrades are dnf install against the next release's package rather than dnf update. /var/lib/caravel deliberately survives an erase once it holds data — your trips are not something a package removal should take with it.

A prebuilt binary

Every release carries a static Linux binary for amd64 and arm64 on its releases page, with a SHA256SUMS file beside them. There is nothing to install alongside it — the frontend is embedded and SQLite is pure Go, so the binary has no libc or library dependencies at all:

tar xzf caravel-1.0.0-linux-amd64.tar.gz
./caravel

It reads the same environment variables as everything else, so a real installation is that binary plus a systemd unit and an EnvironmentFile.

From source

The development path, and also fine for running it. Needs Go 1.26:

make run

That builds and runs the server against a SQLite database created at data/caravel.db, serving on http://localhost:8080, with uploads in uploads/. Both directories are created for you.

For frontend work, make dev serves web/ from disk instead of the copy embedded in the binary, so an edit to anything under web/ needs only a browser refresh. Backend changes still need a restart.

Checking it is running

The container has a healthcheck, and the endpoint behind it reports which build is actually running:

curl http://localhost:8080/api/health
{"status":"ok","version":"v1.0.0"}

That version string is stamped into the binary at build time, which makes "which build is this?" answerable on a running instance rather than a guess from the tag you think you deployed.