Migrate
The migration story already lives in the README; this page pulls the three sections a team moving a project onto viv actually needs, kept in sync with the README at build time.
The composer shim
From the README: Using viv as composer
make install-shim installs a composer binary next to viv (plain
make install leaves your real Composer untouched). Put it on PATH
ahead of the real Composer, or symlink it as composer in CI: everyday
install, dump-autoload, normalize and create-project run through
viv; every other command falls through to your real Composer install.
This is also the cheapest way to check whether a project migrates cleanly:
alias composer to the shim and run your existing scripts unedited.
A command or flag the shim doesn't understand falls back to the real
Composer with a note on stderr naming what wasn't understood, so a migration
that quietly stopped using viv is visible instead of just slower. Set
VIV_SHIM_STRICT=1 to make that fallback a hard error instead, for a CI job
that wants a red build rather than a silent return to Composer.
You can also point a script straight at viv. The CI idiom
--prefer-dist --no-interaction --no-progress already describes what viv
does, so viv install and viv dump-autoload accept those flags and
ignore them instead of failing.
In a Dockerfile
From the README: In a Dockerfile
To build a vendor/ stage without a PHP runtime, use the published image
in place of composer:2:
FROM ghcr.io/svandragt/vivace:0 AS vendor
COPY composer.json composer.lock ./
RUN ["viv", "install", "--no-dev"]
FROM php:8.4-fpm
COPY --from=vendor /app/vendor /app/vendor
Two things differ from the composer:2 stage it replaces:
- Write
RUNin exec form, as above. The image has no shell, so the familiarRUN viv install --no-devdoes not work. - The image runs
vivby default and ships thecomposershim beside it, soRUN ["composer", "install", "--no-dev"]works too if you would rather not edit the command. - The image carries no real Composer to fall back to, so a command or flag the shim doesn't understand hard-errors there instead of silently running Composer, the way it would on a machine that still has Composer installed.
Tags are :0.13, :0.13.0 and :0. There is no :latest: a moving tag
that silently resolves to nothing breaks scripted installs, which is the
mistake that kept releases/latest returning 404 for ten releases.
CI flags
From the README: Using viv as composer
A script that already runs Composer with --prefer-dist --no-interaction
--no-progress needs no changes: viv install and viv dump-autoload
accept those flags and ignore them, the same way they do for Composer.
--ignore-platform-reqs is a real flag on both tools, not a no-op.
The one behaviour that differs: a plugin outside viv's native list stops
the install with an error naming the plugin, loudly, rather than silently
skipping its work. --no-plugins turns that into a warning and installs
the way Composer's own --no-plugins would — see
docs/plugin-strategy.md
for which plugins that's safe for.
What's not covered
For the commands listed in the README's Scope
section, viv writes a vendor/ directory — including vendor/composer/* —
and, for update, update-lock and require/remove, a composer.lock
that are byte-identical to what Composer 2.10 (the version pinned in
devbox.json) writes for the same composer.json, lock file and cache
state. This is the contract, not an implementation detail: if viv's output
differs from Composer's for a covered command, that's a bug.
source: docs/stability.md