Download Latest Version 6.1.0 source code.zip (14.8 MB)
Home / 6.0.0
Name Modified Size InfoDownloads / Week
Parent folder
6.0.0 source code.tar.gz 2026-11-12 14.8 MB
6.0.0 source code.zip 2026-11-12 14.8 MB
README.md 2026-11-12 14.0 kB
Totals: 3 Items   29.6 MB 0

VRT 6.0 flags rendering noise, lets you undo a decision and comes with a redesigned UI.

It is also the most secure VRT so far.

[!IMPORTANT] Upgrading from 5.x? The database moves to PostgreSQL 18. UI and API are upgraded together. Read Breaking changes, then follow Upgrade steps.

Highlights

Redesign

A new UI in light and dark, built around your projects.

  • Project page with tabs: Builds, Variations, Statistics, Settings.
  • Run list: filter chips, table or grid, bulk actions, comments at a glance.
  • Run dialog: Side by side, Diff and Fade, plus edit mode for ignore areas.
  • Undo approval and Undo rejection, also from the toast after bulk actions.
  • Favourites: star a project to pin it to the top of the list and the switcher.
  • Statistics: results per build, with a branch filter.
  • Users page: search, role filter, joined date.
  • Dark mode follows your system until you pick one.

The test run dialog in the dark theme

Performance

Image comparison no longer blocks the API.

  • Diffs run in a worker pool, off the event loop.
  • The pool has CPUs − 1 workers (1 to 8) and queues up to 256 jobs.
  • A full queue answers 503 instead of stalling.
  • Three new indexes, built without blocking writes, speed up large projects.
  • Nightly cleanup runs once and ages branches by last use.

Security

Secure by default.

  • JWT_SECRET is required; the public sample key is refused.
  • Live updates need a login and reach only people viewing that project or build.
  • Containers run unprivileged: uid 1000, dinov2 as nobody.
  • REGISTRATION_ENABLED=false turns off sign-up.
  • A leak of approvers' API keys and password hashes is closed (details).

Noise

Review the real changes first.

  • Run Analyse noise from the build menu, the selection bar or a run's noise chip.
  • Each unresolved run gets a verdict: Likely change or Likely noise.
  • It is a hint: it never changes a status and never approves anything.
  • Off by default; switch it on in project Settings → Post-analysis.
  • Stage one is blur, on the API server.
  • Stage two is optional DINOv2: image visualregressiontracker/dinov2, compose profile dinov2.
  • Point the API at it with DINOV2_URL; start it with docker compose --profile dinov2 up -d.

A build with Likely change and Likely noise labels

Upgrade in one sentence

Dump PostgreSQL 12, restore into PostgreSQL 18, set JWT_SECRET, then start 6.0.

Container versions

:::env
VRT_UI_VERSION=6.0.0
VRT_API_VERSION=6.0.0
VRT_MIGRATION_VERSION=6.0.0
VRT_DINOV2_VERSION=6.0.0   # optional, profile "dinov2"

New optional settings in .env, commented out with their defaults:

  • REGISTRATION_ENABLED, LOG_LEVEL, MAX_IMAGE_PIXELS, MULTIPART_FILE_SIZE_LIMIT
  • DINOV2_URL and the other DINOV2_*
  • REDIS_URL: needed with more than one API instance, so live updates reach every client

Read by the API but not passed by docker-compose.yml; add them to its api environment:

  • HTTPS_KEY_PATH, HTTPS_CERT_PATH
  • DIFF_WORKER_MAX_HEAP_MB, SERVER_HEADERS_TIMEOUT

See Configuration.

New

Compose and install

  • postgres:18; the api starts after migration has finished.
  • Optional dinov2 service (profile dinov2).
  • vrt-install.sh uses Compose v2 and creates ./imageUploads for uid 1000.
  • User docs live in the wiki, linked from the Help menu.

UI

  • Variations: filters and the baseline history of each screen.
  • Add project page, sectioned project settings, profile page with API key regenerate.
  • Build header shows status counters.
  • Project list: press / to search.
  • Undoing a feature-branch approval restores that branch's ignore areas and comment.

API

  • GET /projects/favorites, PUT|DELETE /projects/:id/favorite
  • POST /test-runs/revert: 204, or 409 if the status changed
  • POST /test-variations/merge: merge branches
  • GET /statistics/results: run counts per build
  • GET /dinov2/status
  • User summaries include createdAt.
  • Bulk approve, reject and delete report the result of each run.

Breaking changes

Install and runtime

  • PostgreSQL 18 cannot read a PostgreSQL 12 data directory: dump and restore once.
  • An external database is not affected; 12 still works but is end of life, so move to 15+.
  • The API and migration run as uid 1000. On Linux, chown ./imageUploads (and mounted TLS files).
  • Without it the API stops with EACCES.
  • The image command is now node dist/main under tini; check it if you override command or entrypoint.
  • JWT_SECRET is required; the API refuses the public sample value.
  • Everyone signs in again once; API keys keep working.
  • UI and API ship together. UI 6.0 needs API 6.0.
  • UI 5.x gets no live updates from API 6.0 and misreads its bulk results.
  • DIFF_WORKERS_COUNT and DIFF_QUEUE_LIMIT are no longer read.
  • Under a CPU quota below the host's CPU count, the worker count cannot be lowered.
  • DIFF_WORKER_MAX_HEAP_MB stays.
  • Docker Compose v2 and Node 26.

Noise

  • Only blur.enabled and dinov2.enabled of noiseAnalysisConfig are read.
  • Other thresholds are constants; old keys are accepted and ignored.

API

  • Errors are 4xx, not 200/500:
  • 400 validation
  • 404 missing
  • 409 conflict
  • 413 too large
  • 422 image over MAX_IMAGE_PIXELS (100 MP)
  • 503 diff queue full
  • Check clients that treat any 2xx as success.
  • Error bodies are { statusCode, path, name, message }.
  • /health returns 503 without the database.
  • Stricter uploads:
  • Non-PNG screenshots get 400.
  • GET /images/:name refuses unexpected names with 400.
  • Multipart uploads are capped at MULTIPART_FILE_SIZE_LIMIT (100 MB).
  • Live updates (socket.io):
  • Send auth: { token } and join the project or build room.
  • testRun_* payloads are TestRunDto.
  • A socket closes when its token expires.
  • Removed endpoints:
  • GET /test-variations/merge: use POST with { projectId, fromBranch, toBranch }.
  • PATCH /builds/:id/approve: use POST /test-runs/approve.
  • POST /ollama/compare; GET /ollama/models stays.
  • PATCH /builds/:id rejects unknown fields.
  • PATCH /test-runs/update/:id accepts only comment; unknown fields are dropped everywhere.
  • Deleting users is all or nothing.
  • The UI logs you out when the server closes the live connection.

Results and database

  • Comparison results can change:
  • The project's comparison config is applied over the defaults.
  • pixelmatch treats different sizes as different.
  • looks-same honours diffTollerancePercent.
  • odiff is 4.5.0.
  • TLS to PostgreSQL only when DATABASE_URL asks (?sslmode=require).
  • sslmode=prefer now means require.
  • pgbouncer, statement_cache_size, socket_timeout, sslidentity, sslpassword are ignored (Prisma 7).
  • SSO: OIDC_REDIRECT_URI must not contain a query string.

Removed

  • The Merge branches panel (the API stays).
  • The guided tour; the Help menu links to the documentation.

Clients

The 6.0.0 SDKs and agents are released for this server. They need newer runtimes; on older ones the latest 5.x releases keep working with 6.0 and handle its statuses and error codes.

Client 6.0 release Runtime Or, on an older runtime Why that 5.x
sdk-js 6.0.0 Node.js 26 5.9.0 sourceBranch; clear 404/409/413/422/503 messages; S3 image URLs
agent-cypress 6.0.0 Node.js 26 5.9.0 sourceBranch / VRT_SOURCEBRANCH
agent-playwright 6.0.0 Node.js 26 5.5.0 sourceBranch / VRT_SOURCEBRANCH
agent-codeceptjs 6.0.0 Node.js 26 5.0.0 sdk-js 5, CodeceptJS 3.7
sdk-java 6.0.0 Java 25 5.6.1 stops builds correctly; branchName from the build
sdk-python 6.0.0 Python 3.15 5.1.0 4.9.0 and earlier crash on autoApproved; Python 3.10+
sdk-dotnet 6.0.0 .NET 10 5.1.0 .NET 10; stops builds correctly; image URLs
  • baselineBranchName never had an effect; use sourceBranch (sdk-js 5.8.0+).
  • Screenshots over BODY_PARSER_JSON_LIMIT (5 MB in .env) get 413.
  • sdk-js and agent-cypress can upload them as multipart.

Security

[!WARNING] From api 4.16.0 to 5.7.0, GET /test-variations/details/:id leaked approvers' API keys and password hashes. Any signed-in user, guests included, could read them. If untrusted users could sign in, change those users' passwords. Then regenerate their API keys (profile page → Regenerate).

  • GET /images/%2F… no longer redirects to another site.
  • Before 6.0, an editor's API key could rewrite a build's branchName, number, status or projectId.
  • /ollama/* needs an admin or editor login.
  • GET /users/all and role changes no longer return other users' API keys.
  • The Gemini API key is masked in project responses.
  • .env still ships sample DEFAULT_USER_PASSWORD and DEFAULT_USER_API_KEY: change both before exposing VRT.

Fixed

  • Comparison: different sizes, looks-same tolerance, odiff results, project config over defaults.
  • Branches:
  • Editing a feature-branch run no longer changes main's variation.
  • Merging into an older variation works.
  • Variations list in a stable order.
  • Builds:
  • An empty PATCH /builds/:id stops the build again.
  • maxBuildAllowed never removes the reused build.
  • VLM: ignore areas are masked in images sent to the model; stale VLM text is cleared.
  • API:
  • POST /test-runs to a missing project returns 404.
  • A run that cannot be compared is refused before it is stored.
  • OIDC trusts the issuer the provider advertises.
  • dinov2 answers 503 / 413 past DINOV2_MAX_QUEUE / DINOV2_MAX_PIXELS.
  • UI:
  • Bulk actions act only on the selected runs.
  • Ignore areas stay inside the image.
  • Hotkeys and Escape work in the run dialog.
  • Guests no longer see project edit controls.
  • Tag filters search their own field.

Upgrade steps

Run in the VRT folder (Linux, macOS or WSL).

  1. Dump the database with UI and API stopped: sh docker compose stop ui api docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" -Fc "$POSTGRES_DB"' > vrt-pg12.dump docker compose down && mv db db-pg12
  2. Take .env and docker-compose.yml from this release.
  3. Keep your values; keep the old files for a rollback.
  4. Set JWT_SECRET (openssl rand -hex 32).
  5. Change DEFAULT_USER_PASSWORD and DEFAULT_USER_API_KEY if they are the samples.
  6. Restore into PostgreSQL 18: sh docker compose up -d --wait postgres docker compose exec -T postgres sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --exit-on-error' < vrt-pg12.dump
  7. Linux only: sudo chown -R 1000:1000 ./imageUploads (and your TLS files, if mounted).
  8. Start: docker compose pull && docker compose up -d.
  9. The migration service updates the schema before the API starts.
  10. From 5.5 or later it applies four migrations: three concurrent indexes, then upgrade_to_6_0_0.
  11. Check that docker compose logs migration ends with All migrations have been successfully applied.
  12. Check that the Help menu shows 6.0.0.
  13. Delete ./db-pg12 and vrt-pg12.dump.

Rollback:

  1. docker compose down
  2. mv db db-new && mv db-pg12 db
  3. Restore the old .env and docker-compose.yml.
  4. docker compose up -d

Data written on 6.0 is lost.

If an index build fails (P3009, the migration container keeps restarting) A cancelled `CREATE INDEX CONCURRENTLY` (for example a `statement_timeout`) leaves an invalid index. 1. Find the invalid index: ```sh docker compose exec -T postgres sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "select indexrelid::regclass from pg_index where not indisvalid"' ``` 2. Drop it: ```sh docker compose exec -T postgres sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "DROP INDEX CONCURRENTLY \"TestRun_testVariationId_idx\""' ``` 3. Mark its migration as rolled back: ```sh docker compose run --rm --entrypoint npx migration \ prisma migrate resolve --rolled-back 20261024174953_add_test_run_test_variation_index ``` 4. Run the migrations again: `docker compose up -d migration api` | Index | Migration | |---|---| | `TestRun_testVariationId_idx` | `20261024174953_add_test_run_test_variation_index` | | `Baseline_testVariationId_createdAt_idx` | `20261024175021_add_baseline_test_variation_index` | | `TestRun_name_baselineName_idx` | `20261024175038_add_test_run_name_baseline_name_index` |

PostgreSQL

  • Bundled database: PostgreSQL 18, volume ./db:/var/lib/postgresql.
  • Your own PostgreSQL 12 still works but is end of life; move to 15+.
  • Only the bundled postgres service needs the dump and restore above.

Component releases

Full Changelog: https://github.com/Visual-Regression-Tracker/Visual-Regression-Tracker/compare/5.9.0...6.0.0

Source: README.md, updated 2026-11-12