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:

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