Skip to content

Release history

Vendure releases

A headless commerce framework.

All releases

9 shown

Review required
v3.6.4 Breaking risk
RBAC RCE / SSRF

graphql revert, security hardening, dashboard fixes, perf wins

v3.6.3 Bug fix
Notable features
  • Romanian translations added to the dashboard
  • Bulk cancel action with human‑readable duration strings
Full changelog

Highlights

This patch release lands a substantial round of stability, concurrency and dashboard fixes. The headline items address race conditions in promotion and coupon handling, prevent out-of-memory issues on large channel assignments, and harden the scheduled-task and state-machine subsystems against duplicated or partially-applied work. Thanks as ever to everyone who reported issues and contributed PRs.

Concurrency and integrity fixes

This release closes several long-standing edge cases that could cause data integrity issues under load or concurrent traffic:

  • Coupon usage limits enforced under concurrent checkout (#4660) -- A race condition allowed customers to bypass the per-coupon usage limit when multiple checkouts completed concurrently. The check is now serialised correctly so the configured limit is always respected.
  • Auto-applied promotion usage limits enforced (#4405) -- Promotions that auto-apply (no coupon code required) were not honouring their configured usage limits. They now respect the same limits as code-applied promotions.
  • Atomic state-machine transitions on hook failure (#4689) -- If a state-transition hook threw after the entity state had been written, the entity could be left in an inconsistent state with hooks partially applied. Transitions are now atomic — a failing hook reverts the state change cleanly.
  • No duplicate execution of fast scheduled tasks (#4681) -- Scheduled tasks running on a short interval could be picked up and executed by multiple workers in the same window. The scheduler now correctly deduplicates these executions.

Performance and scalability

  • Avoid OOM on large product-to-channel operations (#4669) -- assignProductsToChannel and removeProductsFromChannel now use a query relation strategy that no longer hydrates the full product graph into memory. This unblocks customers who hit out-of-memory crashes when assigning thousands of products to a channel.
  • Job queues now created in onModuleInit (#4680) -- Moving job-queue creation from onApplicationBootstrap to onModuleInit means queues exist before any other module's bootstrap code runs, eliminating a class of "queue not found" startup races.

Core fixes

  • Asset update with custom field relations (#4696) -- Updating an Asset that had a custom-field relation defined no longer fails. This pairs with the corresponding dashboard fix (#4695).
  • Entity hydrator handles undefined relations (#4672) -- Hydrating an entity where a requested relation was undefined no longer throws.
  • Customer user resolution via relation (#4468) -- The Customer.user resolver now uses the configured relation instead of doing a separate email-based lookup, fixing edge cases where the email had been changed on the user record.
  • Admin UI handles tokenMethod array form (#4663, fixes #4656) -- When tokenMethod is configured as an array (['cookie', 'bearer']), the generated ui-config now serialises it correctly instead of producing an invalid value.

Dashboard fixes and improvements

  • Asset save with custom fields (#4695) -- Saving an Asset with custom fields defined now works correctly from the dashboard.
  • Action bar positioning relative to extensions (#4676) -- Extensions can now position action bar items relative to other extensions rather than only to built-in items, giving extension authors more control over toolbar layout.
  • Graceful fallback on denied replace-extension (#4694) -- When a permission check denies a replace-style extension, the dashboard now falls back to the original block instead of rendering nothing.
  • Custom-page permission checks (#4679) -- Custom pages now respect their declared requiredPermissions and won't render for users who lack them.
  • isFullWidth metadata prop implemented (#4638) -- PageBlocks can now opt into a full-width layout via metadata, useful for components like rich text editors.
  • Direct @base-ui/react imports dropped (#4697) -- Dashboard internals no longer import directly from @base-ui/react, going through the wrapped component layer instead. This keeps the public surface area consistent for extension authors.
  • Order modification preview includes nested fragments (#4640) -- Modification previews now include all required nested fields, so the preview matches what the modification will actually produce.
  • Draft order mutation error messages (#4381) -- updateOrder* mutations on draft orders now surface their error messages to the UI rather than failing silently.
  • Promotions list default sort (#4688) -- The promotions list now opens with a sensible default sort instead of arbitrary order.
  • Chart widget dynamic Y-axis width (#4516) -- The dashboard chart widget now sizes its Y-axis dynamically so long labels are no longer clipped.
  • Empty customFields selection handled (#4652) -- Custom-field components with no selection no longer throw.
  • Fulfillment arg defaults are strings (#4658) -- Fulfillment handler argument default values are now correctly stringified.
  • Tanstack router generator stability (#4666) -- Inlining the route literal sidesteps a tanstack router-generator quirk that could produce broken route trees in certain layouts.

New dashboard features

  • Bulk cancel action with human-readable durations (#4361) -- Order lists now expose a bulk-cancel action, and durations are rendered as human-readable strings (e.g. "3 days ago") rather than raw timestamps.
  • Romanian translations (#4598) -- Romanian (ro) is now supported in the dashboard.

i18n improvements

  • Italian translations updated (#4645) -- A round of missing Italian (it) strings has been added.
  • Swedish corrections (#4684) -- Several mistranslated Swedish (sv.po) strings have been corrected.
  • Wrong-language msgstrs repaired (#4685) -- A bulk fix across hr, nb, tr, it, ja, ko, he and ro removes msgstr entries that had drifted into the wrong language. The i18n:apply script has been hardened to prevent recurrences.

Plugins

  • BullMQJobQueuePlugin filtering (#4523) -- Job filtering in the BullMQ plugin now produces correct results when combining multiple filter fields.

What's Changed

  • fix(ci): Remove [skip ci] from generate_docs workflow by @oliverstreissi in https://github.com/vendurehq/vendure/pull/4646
  • fix(ci): Add gate job to unblock non-package PRs by @michaelbromley in https://github.com/vendurehq/vendure/pull/4649
  • fix(docs): Fix broken links and outdated type names in custom form components docs by @gabriellbui in https://github.com/vendurehq/vendure/pull/4648
  • docs: Fix typo in navigation-menu arrayToTree code snippet by @gabriellbui in https://github.com/vendurehq/vendure/pull/4593
  • fix(core): Enforce usage limits for auto-applied promotions by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4405
  • fix: Add missing include nested fragments in order modification preview by @Ryrahul in https://github.com/vendurehq/vendure/pull/4640
  • fix: Add dynamic y axis width by @Ryrahul in https://github.com/vendurehq/vendure/pull/4516
  • feat(dashboard): Add Romanian translations by @alingabrieldm in https://github.com/vendurehq/vendure/pull/4598
  • fix: Add recursive flatten job filter for bull mq when filter is sent… by @Ryrahul in https://github.com/vendurehq/vendure/pull/4523
  • fix: Make tab view scrollable by @Ryrahul in https://github.com/vendurehq/vendure/pull/4644
  • feat(dashboard): Add bulk cancel action and human-readable duration t… by @Ryrahul in https://github.com/vendurehq/vendure/pull/4361
  • chore: Bump @vendure-io/docs-generator to 0.1.1 by @michaelbromley in https://github.com/vendurehq/vendure/pull/4664
  • fix(admin-ui): Handle tokenMethod array form when generating ui-config (#4656) by @Draykee in https://github.com/vendurehq/vendure/pull/4663
  • fix(dashboard): Inline route literal for tanstack router-generator by @michaelbromley in https://github.com/vendurehq/vendure/pull/4666
  • fix(core): Avoid OOM in product-to-channel assign/remove via query relation strategy by @arthur-nesterenko in https://github.com/vendurehq/vendure/pull/4669
  • chore: Migrate package management from npm to Bun by @michaelbromley in https://github.com/vendurehq/vendure/pull/4675
  • fix(core): Create job queues in onModuleInit instead of onApplicationBootstrap by @michaelbromley in https://github.com/vendurehq/vendure/pull/4680
  • fix(core): Prevent coupon usage limit bypass via concurrent checkout race condition by @grolmus in https://github.com/vendurehq/vendure/pull/4660
  • fix(core): Resolve customer user via relation instead of email lookup by @grolmus in https://github.com/vendurehq/vendure/pull/4468
  • fix(dashboard): Support action bar positioning relative to extensions by @izumi0uu in https://github.com/vendurehq/vendure/pull/4676
  • chore: Add local asset storage strategy and its factory to exports by @DanielBiegler in https://github.com/vendurehq/vendure/pull/4671
  • fix(core): Handle undefined relation in entity hydrator by @izumi0uu in https://github.com/vendurehq/vendure/pull/4672
  • fix(dashboard): Handle empty customFields selection when all fields h… by @Ryrahul in https://github.com/vendurehq/vendure/pull/4652
  • fix(dashboard): Add missing Italian translations by @claudiolor in https://github.com/vendurehq/vendure/pull/4645
  • feat(dashboard): implement isFullWidth metadata prop by @casperiv0 in https://github.com/vendurehq/vendure/pull/4638
  • fix(dashboard): Repair wrong-language msgstrs across hr/nb/tr/it/ja/ko/he/ro and harden i18n:apply by @michaelbromley in https://github.com/vendurehq/vendure/pull/4685
  • fix(dashboard): correct mistranslated Swedish strings in sv.po by @comega-johan in https://github.com/vendurehq/vendure/pull/4684
  • fix(dashboard): Ensure fulfillment arg default value is a string by @kyunal in https://github.com/vendurehq/vendure/pull/4658
  • chore(dashboard): Add error messages to update draft mutations by @LucidityDesign in https://github.com/vendurehq/vendure/pull/4381
  • fix(core): Make state-machine transitions atomic on hook failure by @michaelbromley in https://github.com/vendurehq/vendure/pull/4689
  • fix(dashboard): set default sort on promotions list by @casperiv0 in https://github.com/vendurehq/vendure/pull/4688
  • fix(core): Prevent duplicate execution of fast scheduled tasks by @BibiSebi in https://github.com/vendurehq/vendure/pull/4681
  • fix(dashboard): Check required permissions when rendering custom page… by @LucidityDesign in https://github.com/vendurehq/vendure/pull/4679
  • fix(dashboard): Fall back to original on denied replace extension by @michaelbromley in https://github.com/vendurehq/vendure/pull/4694
  • fix(dashboard): Align asset mutation selection set with other detail pages by @michaelbromley in https://github.com/vendurehq/vendure/pull/4695
  • fix(core): Save Asset before running custom-field relation updates by @michaelbromley in https://github.com/vendurehq/vendure/pull/4696
  • chore(dashboard): Drop direct @base-ui/react imports by @michaelbromley in https://github.com/vendurehq/vendure/pull/4697

New Contributors

  • @arthur-nesterenko made their first contribution in https://github.com/vendurehq/vendure/pull/4669
  • @izumi0uu made their first contribution in https://github.com/vendurehq/vendure/pull/4676
  • @claudiolor made their first contribution in https://github.com/vendurehq/vendure/pull/4645
  • @comega-johan made their first contribution in https://github.com/vendurehq/vendure/pull/4684

Full Changelog: https://github.com/vendurehq/vendure/compare/v3.6.2...v3.6.3

v3.6.2 Security relevant
⚠ Upgrade required
  • Update to v3.6.2 (or respective patched versions v3.5.7, v2.3.4) as soon as possible.
  • Patches are available for older supported branches: v3.5.x → v3.5.7, v2.3.x → v2.3.4.
Security fixes
  • GHSA-9pp3-53p2-ww9v — Fixed SQL injection via languageCode query parameter and sanitized search terms for Postgres tsquery syntax
Full changelog

This is a high-priority security patch that addresses a vulnerability that was reported a few days ago, described in https://github.com/vendurehq/vendure/security/advisories/GHSA-9pp3-53p2-ww9v

You should update your Vendure version as soon as possible. Due to the severity of this vulnerability, we have also published patches for older versions for those who cannot yet update to the latest v3.6.x version:

  • v3.6.x -> v3.6.2
  • v3.5.x -> v3.5.7
  • v2.3.x -> v2.3.4

Thank you to @jacobfrantz1 for responsibly disclosing this issue.

What's Changed

  • core Fix SQL injection via languageCode query parameter (3ff0bc1)
  • core Sanitize search term for Postgres tsquery syntax (32c947d)
  • fix: Use shipping line tax instead of channel tax by @Ryrahul in https://github.com/vendurehq/vendure/pull/4624

Full Changelog: https://github.com/vendurehq/vendure/compare/v3.6.1...v3.6.2

v3.6.1 Bug fix
Notable features
  • Allow creating single‑variant products without requiring option groups
  • Dashboard widgets can specify `requiresPermissions` (e.g., gating order widgets behind `ReadOrder`)
  • Support Zod v4 and re‑export Zod from `@vendure/dashboard`
Full changelog

Highlights

This patch release addresses some important issues that were flagged by our community after the recent v3.6.0 release. Thank you to everyone who contributed issue reports and PRs with fixes!

Product creation flow improvements

This release includes several fixes and improvements to the product creation experience in the dashboard:

  • Single-variant products no longer require option groups (#4616) -- You can now create a product with a single variant directly, without needing to set up option groups first. This simplifies the workflow for products that don't have multiple options (e.g. sizes, colors).
  • Validation no longer blocks unchecked variant rows (#4610) -- Previously, unchecked (excluded) variant rows in the creation form could still trigger validation errors, preventing you from saving. These rows are now correctly skipped during validation.
  • Fixed option group edit link on variant detail page (#4620) -- The link to edit an option group from the variant detail page was broken; this is now corrected.

CLI codemod fix

  • tsconfig resolution in the migration codemod (#4599) -- The @vendure/cli codemod for migrating dashboard extensions now correctly resolves tsconfig.json by walking up from the target directory rather than only looking in the current working directory. This fixes failures when running the codemod from a different directory than where the tsconfig lives.

Core fixes

  • Product channel assignment (#4618) -- assignProductsToChannel was not correctly assigning the Product entity itself to the target channel, only its variants. This is now fixed.
  • Order splitting channel deduplication (#4632) -- When an order's channel matched the default channel, the OrderSplitter could produce duplicate channel entries, causing issues downstream. Channels are now correctly deduplicated.

Dashboard fixes and improvements

  • Toaster z-index stacking (#4634) -- Toast notifications are now portalled to document.body, fixing an issue where they were hidden behind dialogs due to CSS stacking context isolation.
  • Address dialog scrollability (#4622) -- The address dialog is now scrollable with a max height, fixing overflow issues on smaller screens.
  • Query key invalidation (#4630) -- Fixed a cache invalidation mismatch that could cause stale data after mutations.
  • Zod v4 support (#4607) -- The dashboard now supports Zod v4 and re-exports Zod from @vendure/dashboard, so extensions don't need to manage their own Zod dependency.
  • Dashboard widget permissions (#4627) -- Dashboard widgets can now specify requiresPermissions, restoring a capability from the legacy Angular admin UI. The built-in order widgets are now gated behind ReadOrder.

What's Changed

  • ci: Fix Playwright install in publish_and_install workflow by @michaelbromley in https://github.com/vendurehq/vendure/pull/4603
  • ci: Use cd instead of working-directory for Playwright install by @michaelbromley in https://github.com/vendurehq/vendure/pull/4605
  • feat(dashboard): Support Zod v4 and re-export Zod from @vendure/dashboard by @dlhck in https://github.com/vendurehq/vendure/pull/4607
  • fix(ci): Remove [skip ci] from docs manifest commit to unblock PR checks by @dlhck in https://github.com/vendurehq/vendure/pull/4611
  • fix(dashboard): Use index-based identification for collection filters by @grolmus in https://github.com/vendurehq/vendure/pull/4428
  • fix(dashboard): Skip validation for unchecked variant rows by @michaelbromley in https://github.com/vendurehq/vendure/pull/4610
  • chore(dashboard): Sync i18n catalogs by @michaelbromley in https://github.com/vendurehq/vendure/pull/4613
  • fix(cli): Resolve tsconfig by walking up from target directory by @michaelbromley in https://github.com/vendurehq/vendure/pull/4599
  • fix(dashboard): Fix collection filter e2e test selector by @michaelbromley in https://github.com/vendurehq/vendure/pull/4615
  • feat(dashboard): Allow creating single variant without option groups by @michaelbromley in https://github.com/vendurehq/vendure/pull/4616
  • fix(ci): Tolerate i18n line reference changes in sync check by @michaelbromley in https://github.com/vendurehq/vendure/pull/4617
  • fix(core): Assign Product entity to channel in assignProductsToChannel by @michaelbromley in https://github.com/vendurehq/vendure/pull/4618
  • fix(dashboard): Fix option group edit link on variant detail page by @michaelbromley in https://github.com/vendurehq/vendure/pull/4620
  • refactor: Replace local docs generation code with @vendure-io/docs-generator by @oliverstreissi in https://github.com/vendurehq/vendure/pull/4626
  • fix: Make address dialog scrollabe with max h by @Ryrahul in https://github.com/vendurehq/vendure/pull/4622
  • fix: Match query key invalidation by @Ryrahul in https://github.com/vendurehq/vendure/pull/4630
  • fix(core): Deduplicate channels in OrderSplitter when channelId matches default (#4631) by @Draykee in https://github.com/vendurehq/vendure/pull/4632
  • fix: Add creator portal in toaster to avoid isolation:isolate stacking by @Ryrahul in https://github.com/vendurehq/vendure/pull/4634
  • feat(dashboard): Add requiresPermissions support to dashboard widgets by @niko91i in https://github.com/vendurehq/vendure/pull/4627

Full Changelog: https://github.com/vendurehq/vendure/compare/v3.6.0...v3.6.1

v3.6.0 Breaking risk
⚠ Upgrade required
  • Back up the database before migration. Run `npx vendure migrate --generate v36`, then edit the generated migration to insert `migrateProductOptionGroupData(queryRunner)` before dropping the `productId` column and `migrateAssetTranslationData(queryRunner)` before dropping the `name` column.
  • If using ElasticSearch, upgrade your instance to version 9.1.0 and update `@elastic/elasticsearch` dependency accordingly; a full reindex is required.
  • Community plugins must be uninstalled (e.g., `@vendure/elasticsearch-plugin`) and installed from the new `@vendure-community` organization with updated import paths.
Breaking changes
  • ProductOptionGroup and ProductOption are now shared resources with channel awareness (requires migration of option group data).
  • Asset entity becomes translatable; the `name` column is moved to a new `asset_translation` table (migration required).
  • GraphQL `productOptionGroups` query now returns paginated `ProductOptionGroupList` instead of a flat array.
Notable features
  • First‑class API key support for machine‑to‑machine authentication with scoped permissions, rotation, and revocation.
  • Asset now implements the `Translatable` interface; migration helper copies existing names into translations automatically.
  • Configurable order tax calculation via pluggable `OrderTaxCalculationStrategy` (includes `DefaultOrderTaxCalculationStrategy` and new `OrderLevelTaxCalculationStrategy`).
Full changelog

Highlights

Shared Product Option Groups

Option groups are now shared resources — a single "Size" group can be linked to as many products as you need. They're also channel-aware, so multi-tenant setups can scope them per channel. There's a new dedicated management page in the dashboard, and CSV imports handle shared groups out of the box. A migration helper is provided for the data transition.

API Key Authentication

First-class API key support for machine-to-machine authentication. Create a key, scope it to specific permissions, use it in a header. Keys can be rotated and revoked at any time, with a full management UI in the dashboard. Community contribution from Daniel Biegler.

Translatable Assets

Asset now implements the Translatable interface — asset names and custom fields can vary per language. A migration helper copies existing names into translations automatically.

Configurable Order Tax Calculation

Order-level tax calculation is now pluggable via OrderTaxCalculationStrategy. Ships with DefaultOrderTaxCalculationStrategy (same as v3.5) and OrderLevelTaxCalculationStrategy.

Refreshed Dashboard

The dashboard is now built on @vendure-io/ui, our own open-source design system. Same tech stack, refined visual identity. Under the hood, headless primitives migrated from Radix UI to Base UI — all components now live in a single package. New extension points: toolbar items, function-based nav sections, component-based alert actions, improved ActionBar. Translation fallback placeholders for non-default languages. New Hungarian and Dutch translations.

Community Plugins

Several plugins have moved to the @vendure-community npm org with independent versioning. See the migration guide below for the full mapping.

Per-Queue Job Concurrency

Job queue concurrency now accepts a function (queueName: string) => number for per-queue control.

Other Notable Features

  • BootstrappedEvent — fires when the server is fully ready after app.listen()
  • onBeforeAppListen hook — operate on the NestJS app before it starts listening
  • Async email generators
  • setOrderCurrencyCode Shop API mutation
  • Collection search filters (collectionIds, collectionSlugs)
  • Braintree multi-currency support
  • Custom field dashboard: { visible: false } option
  • Settings Store management page
  • Force update payment status
  • EntityAccessControlStrategy (developer preview) — row-level access control

Notable Fixes

  • Dashboard compilation: 2x faster builds, 4x lower memory usage (replaced ts.createProgram with per-file transpilation)
  • Atomic, concurrency-safe mergeOrders
  • Schema-qualified table paths in EXISTS subqueries (multi-schema Postgres fix)
  • Stale shipping line cleanup for deleted shipping methods

Migration Guide

This guide covers all breaking changes and required migration steps when upgrading from v3.5.x to v3.6.0.

1. Database Migration

Back up your database before proceeding. The migration involves moving data between tables, and while the helpers are idempotent and well-tested, a backup is always good practice before a schema change of this scale.

After updating your Vendure packages to v3.6, generate your migration:

npx vendure migrate --generate v36

This generates a migration file in your configured migrations directory. Before starting your application, you need to edit the generated migration file to insert two data migration helpers. If you skip these steps, the auto-generated DDL will drop columns and data will be permanently lost.

1a. Asset Translation Data

The Asset entity is now translatable (#4171). The name column moves from the asset table to a new asset_translation table.

Open your generated migration file and look for the SQL that creates the asset_translation table. Further down in the same file, you'll find a statement that drops the name column from asset. Insert the migrateAssetTranslationData helper call between these two operations.

1b. Shared ProductOptionGroup Data

ProductOptionGroup and ProductOption are now shared resources that can belong to multiple products, and are channel-aware (#4469). The productId FK column on product_option_group is replaced by join tables.

Look for the SQL that creates the new join tables (e.g. CREATE TABLE "product_option_groups_product_option_group"). Further down, you'll find a statement that drops the productId column. Insert the migrateProductOptionGroupData helper call between these two operations.

Putting it together

Here is a real example of a generated Postgres migration with the helpers inserted. Your migration will look similar — the exact SQL and constraint names will vary, but the structure is the same.

import { MigrationInterface, QueryRunner } from 'typeorm';
import {
    migrateAssetTranslationData,
    migrateProductOptionGroupData,
} from '@vendure/core';

export class V361774950673940 implements MigrationInterface {

   public async up(queryRunner: QueryRunner): Promise<any> {
        // ... auto-generated DDL ...
        await queryRunner.query(`CREATE TABLE "asset_translation" ("createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "languageCode" character varying NOT NULL, "name" character varying NOT NULL, "id" SERIAL NOT NULL, "baseId" integer, CONSTRAINT "PK_2f22e63eefeef14d245bdb956b6" PRIMARY KEY ("id"))`, undefined);
        await queryRunner.query(`CREATE INDEX "IDX_4eed4464adef51f53e1c7d8021" ON "asset_translation" ("baseId") `, undefined);
        // ... api_key tables, product_option join tables, etc. ...
        await queryRunner.query(`CREATE TABLE "product_option_groups_product_option_group" ("productId" integer NOT NULL, "productOptionGroupId" integer NOT NULL, CONSTRAINT "PK_6a7a0291e226fbb0d4df828a483" PRIMARY KEY ("productId", "productOptionGroupId"))`, undefined);
        // ... indexes ...

        // *** INSERTED: migrate option group data before productId is dropped ***
        await migrateProductOptionGroupData(queryRunner);

        await queryRunner.query(`ALTER TABLE "product_option_group" DROP COLUMN "productId"`, undefined);

        // *** INSERTED: migrate asset names before name column is dropped ***
        await migrateAssetTranslationData(queryRunner);

        await queryRunner.query(`ALTER TABLE "asset" DROP COLUMN "name"`, undefined);
        // ... remaining DDL (foreign key constraints, etc.) ...
   }

   public async down(queryRunner: QueryRunner): Promise<any> {
        // Auto-generated reverse DDL (no changes needed here)
   }
}

Tip: In a Postgres migration, look for the two DROP COLUMN lines — they'll be close together:

ALTER TABLE "product_option_group" DROP COLUMN "productId"
ALTER TABLE "asset" DROP COLUMN "name"

Insert each helper call immediately before its corresponding DROP COLUMN.

Note for SQLite users: SQLite doesn't support DROP COLUMN directly. TypeORM uses a temporary table pattern instead (create temp table without the column, copy data, drop original, rename). The same principle applies — insert the helpers before the data copy that omits the column — but the SQL will look different.

Both helpers are idempotent — safe to run multiple times without creating duplicate data. If the migration is interrupted partway through, you can re-run it safely.

Run the Migration

Start your application. The default index.ts scaffold calls runMigrations(config) before bootstrap(config), so the migration will be applied automatically on startup.

Alternatively, you can run it explicitly:

npx vendure migrate --run

2. Community Plugins: New Package Names

Several plugins have been moved out of the Vendure monorepo into a dedicated community repo: vendurehq/vendure-community-plugins. They are now published under the @vendure-community npm org with independent versioning, decoupled from Vendure Core releases.

The plugin APIs are unchanged — same classes, same configuration, same behaviour. This is a package rename, not a rewrite.

If you use any of these plugins, uninstall the old package and install the new one:

| Old package (final version) | New package |
|---|---|
| @vendure/[email protected] | @vendure-community/[email protected] |
| @vendure/[email protected] (Stripe) | @vendure-community/[email protected] |
| @vendure/[email protected] (Braintree) | @vendure-community/[email protected] |
| @vendure/[email protected] (Mollie) | @vendure-community/[email protected] |
| @vendure/[email protected] | @vendure-community/[email protected] |
| @vendure/[email protected] | @vendure-community/[email protected] |
| @vendure/[email protected] (pub-sub) | @vendure-community/[email protected] |

For example, to migrate the Stripe plugin:

npm uninstall @vendure/payments-plugin
npm install @vendure-community/[email protected]

Then update all imports in your TypeScript code:

// Before
import { ElasticsearchPlugin } from '@vendure/elasticsearch-plugin';
import { StripePlugin } from '@vendure/payments-plugin/package/stripe';

// After
import { ElasticsearchPlugin } from '@vendure-community/elasticsearch-plugin';
import { StripePlugin } from '@vendure-community/stripe-plugin';

Search your codebase for any remaining references to the old package names — this includes imports, dynamic require() calls, and any configuration files that reference the old packages.

Note: @vendure/job-queue-plugin (BullMQ) remains in core and continues to be published as part of Vendure. Only the pub-sub strategy has moved.


3. ElasticSearch Plugin: Upgrade to v9.1.0

If you use the ElasticSearch plugin (now @vendure-community/elasticsearch-plugin), you must upgrade your ElasticSearch instance from v7.x to v9.1.0 (#3740).

This is a one-way upgrade with no downgrade path. Test in a staging environment first.

Steps:

  1. Upgrade your ElasticSearch instance to v9.1.0. If running via Docker, update your image tag (e.g. elasticsearch:9.1.0).
  2. Update your project's package.json:
    "@elastic/elasticsearch": "9.1.0"
    
  3. The ES database schema migration happens automatically on instance startup.
  4. After the upgrade, run a full reindex via the Admin API or dashboard

The old v7 client is incompatible with v9 and vice versa. Both the plugin and your project must use the v9.1.0 client.


4. Dashboard: Radix UI → Base UI Migration

The dashboard has migrated from Radix UI to Base UI via the new @vendure-io/ui package (#4531).

If you have custom dashboard extensions using Radix UI components, run the provided codemod:

npx vendure codemod dashboard-base-ui <target-directory>

Important: The codemod scans all .tsx files reachable from the tsconfig. In a monorepo with multiple apps (e.g. a Next.js storefront alongside the Vendure server), running it from the repo root will also transform files in non-dashboard projects. This can break those projects — for example, rewriting import { toast } from 'sonner' to import { toast } from '@vendure/dashboard' in a Next.js app.

To avoid this:

  • Run the codemod only on your dashboard extension directories, not the entire repo root. For example:
    npx vendure codemod dashboard-base-ui libs/my-dashboard-plugin/
    npx vendure codemod dashboard-base-ui src/plugins/
    
  • If you do run it from the repo root, review changes in non-dashboard projects and revert them.

The codemod handles import path updates automatically. Component props that differ between Radix and Base UI may need manual adjustment. After running the codemod, check for any remaining TypeScript errors:

npx tsc --noEmit

If you don't have custom dashboard extensions, no action is needed.

[!NOTE]
when specifying a non-root path to your plugins, you may encounter the error No tsconfig.json found in <path>. This is a known issue resolved in the next patch. For now as a workaround you can temporarily copy your dashboard tsconfig file into that directory when running the codemod.


5. Dashboard: Vite v6 → v7

The dashboard's Vite version has been upgraded from v6 to v7 (#4514).

No action required in the typical case. In monorepo environments where other projects depend on a different Vite version, review for potential version conflicts.


6. API & Type Changes

ProductOptionGroups Query — Now Paginated

The productOptionGroups query now returns a paginated ProductOptionGroupList (with items and totalItems) instead of a flat array. It accepts standard ProductOptionGroupListOptions for filtering, sorting, and pagination.

Before (v3.5):

query {
  productOptionGroups(filterTerm: "size") {
    id
    name
  }
}

After (v3.6):

query {
  productOptionGroups(options: {
    filter: { name: { contains: "size" } }
  }) {
    items {
      id
      name
    }
    totalItems
  }
}

The old filterTerm parameter is replaced by the standard filter option, which supports all the usual operators (eq, contains, in, etc.).

Asset Type — Now Translatable

The Asset GraphQL type now includes languageCode and translations fields. CreateAssetInput and UpdateAssetInput accept an optional translations array.

Existing code that reads asset.name will continue to work — the name is resolved from the translation matching the current request language.

OrderMergeStrategy — Now Async

OrderMergeStrategy.merge() return type has been widened to MergedOrderLine[] | Promise<MergedOrderLine[]> (#4436). Existing synchronous implementations still work without changes. If you call merge() directly in custom code, you must now await the result:

// Before
const result = myStrategy.merge(ctx, order, guestOrder);

// After
const result = await myStrategy.merge(ctx, order, guestOrder);

Job Queue Concurrency Type Widened

PollingJobQueueStrategy.concurrency type changed from number to number | ((queueName: string) => number) (#4201). The same applies to BullMQ and PubSub strategies. Existing numeric values still work without changes.


7. Deprecations

Health Check Features

The built-in health check features integration have been deprecated (#4442):

  • HttpHealthCheckStrategy, TypeOrmHealthCheckStrategy, and HealthCheckRegistryService are marked @deprecated
  • The health check page has been removed from the dashboard
  • The health check HTTP endpoint still functions for the server and worker.

Why? Checking all infrastructure dependencies (DB, Redis, etc.) in a single health endpoint is actually an anti-pattern in production environments. The core problem: If your database goes down for a few seconds, the health check fails, and your orchestrator (Kubernetes, ECS, etc.) marks the app as unhealthy and restarts or drains it. Now you have two problems: the DB is down and your app instances are being killed, even though the application process itself is perfectly fine. When the DB recovers, there are no healthy instances left to serve traffic.

The solution is to separate the health checks for each piece of your production infrastructure. The Vendure /health endpoints should only report the health of that instance, independent of all other infrastructure.


8. New Opt-In Features

These are new features that don't require migration, but you may want to be aware of:

Anonymous Telemetry

v3.6 adds opt-out anonymous telemetry. It collects non-identifying usage data (strategy types, plugin adoption, feature flags) to help prioritize development. To disable, set the environment variable:

VENDURE_DISABLE_TELEMETRY=true

Default Search Plugin: Currency Code Index

If you want to index by currency code in the default search plugin, you can now opt in (#3268):

DefaultSearchPlugin.init({
  indexCurrencyCode: true,
})

This changes the primary key of the search index table and requires a full reindex after enabling.


9. Dependency Updates

The following dependencies of @vendure/core have been updated (#4564). You only need to take action if your project directly imports or depends on these packages. If you only interact with them through Vendure's APIs, no changes are needed.

| Package | From | To |
|---------|------|-----|
| bcrypt | 5.x | 6.x |
| better-sqlite3 | 11.x | 12.x |
| mime-types | 2.x | 3.x |
| csv-parse | 5.x | 6.x |
| i18next | 24.x | 25.x |
| image-size | 1.x | 2.x |
| @graphql-tools/stitch | 9.x | 10.x |

Note: bcrypt is a native addon. After upgrading, you may need to run npm rebuild bcrypt if you encounter errors.


Quick Checklist

  • [ ] Back up your database
  • [ ] Update all @vendure/* packages to v3.6.0
  • [ ] Replace community plugin packages (@vendure/elasticsearch-plugin@vendure-community/elasticsearch-plugin, etc.)
  • [ ] Update all imports in TypeScript code to use new community plugin package names
  • [ ] Generate migration: npx vendure migrate --generate v36
  • [ ] Edit migration file: add migrateProductOptionGroupData(queryRunner) before DROP COLUMN "productId"
  • [ ] Edit migration file: add migrateAssetTranslationData(queryRunner) before DROP COLUMN "name"
  • [ ] Start application (or run npx vendure migrate --run) to apply migration
  • [ ] If using ElasticSearch: upgrade instance to v9.1.0, update @elastic/elasticsearch to 9.1.0, run full reindex
  • [ ] If using custom dashboard extensions: run npx vendure codemod dashboard-base-ui <target-dir> then npx tsc --noEmit
  • [ ] If using productOptionGroups query: update to paginated response format
  • [ ] If enabling indexCurrencyCode: run full reindex
  • [ ] Run npm rebuild bcrypt if needed

What's Changed

  • feat(default-search-plugin): add support for 'currencyCode' index by @casperiv0 in https://github.com/vendurehq/vendure/pull/3268
  • feature(elasticsearch-plugin): adds search options by collection slugs or collection IDs by @alexisvigoureux in https://github.com/vendurehq/vendure/pull/3182
  • feat(core): Add collectionIds and collectionSlugs filters to default search plugin by @dlhck in https://github.com/vendurehq/vendure/pull/3945
  • refactor: Update e2e tests to use gql.tada features by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/3974
  • feat(asset-server-plugin): Allow specifying encoding for AssetStorageStrategy by @pujux in https://github.com/vendurehq/vendure/pull/3926
  • feat(core): API Keys by @DanielBiegler in https://github.com/vendurehq/vendure/pull/3815
  • chore: Update the Vendure ElasticSearch plugin to use ElasticSearch v9.1.0 by @LeftoversTodayAppAdmin in https://github.com/vendurehq/vendure/pull/3740
  • chore: Update the Vendure ElasticSearch plugin to use ElasticSearch v9.1.0 by @biggamesmallworld in https://github.com/vendurehq/vendure/pull/4009
  • feat(dashboard): Improved extensibility of ActionBar by @michaelbromley in https://github.com/vendurehq/vendure/pull/4049
  • feat: Add support for asynchronous email generators by @twlite in https://github.com/vendurehq/vendure/pull/3976
  • Mollie: Allow forcefully updating payment status in case webhooks are delayed by @martijnvdbrug in https://github.com/vendurehq/vendure/pull/4104
  • 3909 pvp custom fields not showing by @mehringer68 in https://github.com/vendurehq/vendure/pull/4180
  • feat(core)!: Make Asset entity translatable by @biggamesmallworld in https://github.com/vendurehq/vendure/pull/4171
  • feat(core): Add anonymous telemetry collection module by @dlhck in https://github.com/vendurehq/vendure/pull/4192
  • feat(core,job-queue-plugin): Add per-queue concurrency configuration by @biggamesmallworld in https://github.com/vendurehq/vendure/pull/4201
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4396
  • fix(core): Fix broken e2e test after master merge by @michaelbromley in https://github.com/vendurehq/vendure/pull/4399
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4429
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4433
  • feat(core): Add EntityAccessControlStrategy for row-level access control by @michaelbromley in https://github.com/vendurehq/vendure/pull/4451
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4465
  • feat(core): Add Shop API mutation to set order currency code by @michaelbromley in https://github.com/vendurehq/vendure/pull/4466
  • feat(core): Provide app instance before app starts listening by @LucidityDesign in https://github.com/vendurehq/vendure/pull/4383
  • feat(core): Make ProductOptionGroup & ProductOption shared and channel-aware by @michaelbromley in https://github.com/vendurehq/vendure/pull/4469
  • feat(dashboard): Add Settings Store management page by @michaelbromley in https://github.com/vendurehq/vendure/pull/4473
  • feat(payments-plugin): Add multi currency support for braintree plugin by @kkerti in https://github.com/vendurehq/vendure/pull/3239
  • refactor(core,dashboard): Deprecate built-in health check features by @dlhck in https://github.com/vendurehq/vendure/pull/4442
  • feat(dashboard): Add Option Groups management page by @michaelbromley in https://github.com/vendurehq/vendure/pull/4483
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4489
  • feat(core): Add configurable OrderTaxSummaryCalculationStrategy by @colinpieper in https://github.com/vendurehq/vendure/pull/4376
  • feat(dashboard): Add toolbarItems extension point to app shell header by @michaelbromley in https://github.com/vendurehq/vendure/pull/4496
  • feat(dashboard): Support function form for navSections by @michaelbromley in https://github.com/vendurehq/vendure/pull/4491
  • feat(core): Support shared product option groups in CSV import by @michaelbromley in https://github.com/vendurehq/vendure/pull/4503
  • feat(core): Introduce BootstrappedEvent to signal server readiness by @Draykee in https://github.com/vendurehq/vendure/pull/4498
  • feat(core): Allow async OrderMergeStrategy by @twlite in https://github.com/vendurehq/vendure/pull/4436
  • feat(dashboard): Upgrade Vite from v6 to v7 by @dlhck in https://github.com/vendurehq/vendure/pull/4514
  • fix(dashboard): Add shared-types and shared-utils to Vite optimizeDeps by @dlhck in https://github.com/vendurehq/vendure/pull/4520
  • feat(dashboard): Allow component-based alert actions for hook access by @michaelbromley in https://github.com/vendurehq/vendure/pull/4526
  • refactor(dashboard): Migrate from Radix UI to Base UI via @vendure-io/ui by @dlhck in https://github.com/vendurehq/vendure/pull/4531
  • feat(cli): Add codemod command for Radix to Base UI dashboard migration by @dlhck in https://github.com/vendurehq/vendure/pull/4536
  • fix(dashboard): Follow transitive dependencies in plugin discovery by @michaelbromley in https://github.com/vendurehq/vendure/pull/4545
  • feat(dashboard): Translation fallback placeholders for translatable fields by @dlhck in https://github.com/vendurehq/vendure/pull/4549
  • fix(core): Server-side translation field-level fallback for empty values by @dlhck in https://github.com/vendurehq/vendure/pull/4551
  • fix(dashboard): Fix component styling regressions from Base UI migration by @michaelbromley in https://github.com/vendurehq/vendure/pull/4552
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4555
  • feat(core): Expand telemetry with strategy, integration and feature adoption data by @dlhck in https://github.com/vendurehq/vendure/pull/4554
  • fix(core): Allow admin re-creation after soft-delete by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4543
  • fix(dashboard): Hide dev mode ring offset when not hovered by @michaelbromley in https://github.com/vendurehq/vendure/pull/4558
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4562
  • chore(plugins): Update safe plugin dependencies by @michaelbromley in https://github.com/vendurehq/vendure/pull/4565
  • chore(core): Dependency updates phases 1-3 by @michaelbromley in https://github.com/vendurehq/vendure/pull/4564
  • fix(dashboard): Fix flaky path-alias test and sql.js lockfile resolution by @michaelbromley in https://github.com/vendurehq/vendure/pull/4567
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4568
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4573
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4574
  • fix(dashboard): Align styling with design system tokens by @michaelbromley in https://github.com/vendurehq/vendure/pull/4575
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4579
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4581
  • feat(dashboard): Add API keys management UI by @michaelbromley in https://github.com/vendurehq/vendure/pull/4583
  • fix(dashboard): Fix collection expand e2e test selector by @michaelbromley in https://github.com/vendurehq/vendure/pull/4585
  • feat(core): Add migrateAssetTranslationData() helper for v3.6 upgrade by @michaelbromley in https://github.com/vendurehq/vendure/pull/4584
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4587
  • fix(core): Upgrade i18next to v26 to remove locize promotional message by @michaelbromley in https://github.com/vendurehq/vendure/pull/4588
  • chore(repo): Back-merge master into minor (conflicts) by @github-actions[bot] in https://github.com/vendurehq/vendure/pull/4589
  • fix(core): Restore minor-branch dependency versions after merge by @michaelbromley in https://github.com/vendurehq/vendure/pull/4590
  • chore: Remove community plugins from monorepo by @michaelbromley in https://github.com/vendurehq/vendure/pull/4591
  • fix: Align dashboard and job-queue-plugin versions to 3.5.6 by @michaelbromley in https://github.com/vendurehq/vendure/pull/4592
  • docs: Add API keys developer guide by @michaelbromley in https://github.com/vendurehq/vendure/pull/4595
  • fix(core): Add missing docs annotations and exports for v3.6 APIs by @michaelbromley in https://github.com/vendurehq/vendure/pull/4597

New Contributors

  • @mehringer68 made their first contribution in https://github.com/vendurehq/vendure/pull/4180
  • @LucidityDesign made their first contribution in https://github.com/vendurehq/vendure/pull/4383

Full Changelog: https://github.com/vendurehq/vendure/compare/v3.5.6...v3.6.0

v3.5.6 Breaking risk
⚠ Upgrade required
  • If using a custom `PathAdapter`, set the new `sourceRoot` property to your monorepo workspace root to preserve correct output directory nesting.
Breaking changes
  • `PathAdapter` gets new `sourceRoot` option — in edge cases (custom monorepo path adapters) the default output directory structure flattening can prevent dashboard builds; users must set `sourceRoot` to their workspace root.
Notable features
  • Product options now visible on variant detail page
  • Collection tree expanded/collapsed state persisted in URL
  • Custom fields can be hidden from Dashboard UI via new `dashboard` option
Full changelog

Highlights

This is the final release of the v3.5.x line, before the imminent release of Vendure v3.6!

This release includes a whole host of improvements to the core and dashboard packages.

Note: this is also the final release for the following packages before they are moved to their new homes:

  • @vendure/elasticsearch-plugin
  • @vendure/payments-plugin
  • @vendure/sentry-plugin
  • @vendure/stellate-plugin
  • @vendure/job-queue-plugin/package/pub-sub

Instructions on updating these packages will be included with the v3.6 release notes & migration guide.

Core fixes

  • Atomic order mergingOrderService.mergeOrders is now concurrency-safe, preventing race conditions when multiple requests hit simultaneously
  • Stale shipping lines cleaned up — orders no longer carry phantom shipping lines from deleted shipping methods
  • Schema-qualified EXISTS subqueries — fixes correctness issues in multi-schema PostgreSQL setups
  • Channel cache invalidation — channel token is now set before query invalidation, fixing stale data issues after channel updates
  • Wider TranslationInput typelanguageCode now accepts string literal unions, improving TypeScript ergonomics for custom language handling

Dashboard improvements

  • Product options on variant detail — product options are now visible directly on the variant detail page
  • Collection tree state persisted in URL — expanded/collapsed state survives navigation and page refreshes
  • Custom fields hideable from UI — new dashboard option lets you hide custom fields from the Dashboard without removing them from the API
  • Nested address custom fields — custom fields on customer addresses now render correctly in the customer detail view
  • Breadcrumbs update reactively — breadcrumbs now reflect entity name changes after a save without requiring a page reload
  • Sidebar hover cards for collapsed nav — navigation sections now show a hover card when the sidebar is collapsed
  • Faceted filter wrapping — filters no longer overflow horizontally on narrow screens
  • ConfigurableOperationInput validation fix — args with a defaultValue are now treated as valid even when empty
  • MoneyInput focus & onChange handling — fixes edge cases in the money input component
  • Currency display in order table — correct currency now passed to the Money component in order line items
  • OOM fix in plugin compilation — replaces ts.createProgram() with per-file ts.transpileModule() in the config loader, eliminating heap exhaustion when vendure-config.ts imports plugins with heavy transitive dependencies (e.g. openai, ai, @ai-sdk/*). Compile time drops by up to 98% and memory use by up to 78%.
  • PathAdapter gets new sourceRoot option ⚠️ BREAKING CHANGE IN EDGE CASES — where monorepos using a custom pathAdapter.getCompiledConfigPath cannot build the dashboard because the output directory structure is flattened: If you use a custom pathAdapter, set sourceRoot to your workspace root to restore correct nesting:
  vendureDashboardPlugin({
      pathAdapter: {
          sourceRoot: path.resolve(__dirname, '../..'), // workspace root
          getCompiledConfigPath: ({ outputPath, configFileName }) => {
              return join(outputPath, 'apps', 'vendure-server', 'src', configFileName);
          },
      },
  })

Non-monorepo setups are unaffected — the default behaviour is unchanged.

New translations

What's Changed

  • Feat(dashboard) : nl translations by @LazyClicks in https://github.com/vendurehq/vendure/pull/4188
  • fix(dashboard): Treat args with defaultValue as valid in ConfigurableOperationInput by @michaelbromley in https://github.com/vendurehq/vendure/pull/4462
  • fix(dashboard): Display variant creation errors and list query errors by @grolmus in https://github.com/vendurehq/vendure/pull/4460
  • fix(dashboard): Fix validation & UX issues in product variant option groups by @biggamesmallworld in https://github.com/vendurehq/vendure/pull/4458
  • fix(ci): Pin third-party GitHub Actions to full commit SHAs by @michaelbromley in https://github.com/vendurehq/vendure/pull/4475
  • chore(repo): Address SonarQube low-hanging fruit issues by @michaelbromley in https://github.com/vendurehq/vendure/pull/4477
  • fix(core): Remove stale shipping lines when shipping method no longer exists by @colinpieper in https://github.com/vendurehq/vendure/pull/4487
  • feat(dashboard): Add Hungarian translations by @atistrcsn in https://github.com/vendurehq/vendure/pull/4423
  • fix(testing): Prevent e2e port collisions across packages by @michaelbromley in https://github.com/vendurehq/vendure/pull/4484
  • fix(core): Make OrderService.mergeOrders atomic and concurrency-safe by @michaelbromley in https://github.com/vendurehq/vendure/pull/4488
  • fix(dashboard): Use null instead of undefined when clearing relation custom fields by @grolmus in https://github.com/vendurehq/vendure/pull/4495
  • fix(core): use schema-qualified table paths in EXISTS subqueries by @yasserlens in https://github.com/vendurehq/vendure/pull/4501
  • fix: set channel token before query invalidation by @Ryrahul in https://github.com/vendurehq/vendure/pull/4472
  • fix(dashboard): Show hover card for collapsed sidebar nav sections by @oliverstreissi in https://github.com/vendurehq/vendure/pull/4440
  • fix: Channel cache invalidation after update by @Ryrahul in https://github.com/vendurehq/vendure/pull/4461
  • fix(dashboard): Wrap faceted filters to prevent horizontal overflow by @grolmus in https://github.com/vendurehq/vendure/pull/4467
  • fix(dashboard): Detect plugins compiled with tslib importHelpers by @michaelbromley in https://github.com/vendurehq/vendure/pull/4518
  • fix(dashboard): Forward all ControllerProps in FormFieldWrapper by @gabriellbui in https://github.com/vendurehq/vendure/pull/4513
  • fix(dashboard): Update breadcrumb reactively after entity mutation by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4512
  • chore: Trim CLAUDE.md to implicit knowledge only by @BibiSebi in https://github.com/vendurehq/vendure/pull/4522
  • fix(core): Widen TranslationInput languageCode to accept string literal unions by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4534
  • fix(dashboard): Pass correct currency prop to Money component in order table by @isxwor in https://github.com/vendurehq/vendure/pull/4541
  • feat(core): Add dashboard option to hide custom fields from Dashboard UI by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4544
  • fix(docs): Correct typo in EventBus JSDoc by @latifniz in https://github.com/vendurehq/vendure/pull/4533
  • fix(docs): Correct typo in ProductEvent JSDoc by @latifniz in https://github.com/vendurehq/vendure/pull/4539
  • fix: Add nested address custom field in customer detail by @Ryrahul in https://github.com/vendurehq/vendure/pull/4546
  • fix(ci): Update deploy dashboard workflow to match minor branch by @michaelbromley in https://github.com/vendurehq/vendure/pull/4556
  • fix(dashboard): Replace ts.createProgram with per-file transpilation to prevent OOM by @michaelbromley in https://github.com/vendurehq/vendure/pull/4561
  • fix(dashboard): Use tsconfig baseUrl as source root for monorepo pathAdapters by @michaelbromley in https://github.com/vendurehq/vendure/pull/4570
  • docs: Add manifest.json and compile script by @dlhck in https://github.com/vendurehq/vendure/pull/4572
  • feat(dashboard): Display product options on variant detail page by @grolmus in https://github.com/vendurehq/vendure/pull/4187
  • fix(dashboard): Add missing i18n translations and CI sync check by @michaelbromley in https://github.com/vendurehq/vendure/pull/4578
  • fix(dashboard): Persist collection tree expanded state in URL search params by @biggamesmallworld in https://github.com/vendurehq/vendure/pull/4509
  • fix(dashboard): MoneyInput component to handle focus state and onChange by @harshit078 in https://github.com/vendurehq/vendure/pull/4586

New Contributors

  • @LazyClicks made their first contribution in https://github.com/vendurehq/vendure/pull/4188
  • @atistrcsn made their first contribution in https://github.com/vendurehq/vendure/pull/4423
  • @latifniz made their first contribution in https://github.com/vendurehq/vendure/pull/4533
  • @harshit078 made their first contribution in https://github.com/vendurehq/vendure/pull/4586

Full Changelog: https://github.com/vendurehq/vendure/compare/v3.5.5...v3.5.6

v3.5.5 New feature
Notable features
  • Product and variant lists support filtering by facet value
Full changelog

Release Highlights

This release is mostly focused on continued polish for the React dashboard, with a large batch of fixes including: order line discounts no longer showing [object Object] (#4378), proper disabled state propagation for form inputs (#4425), custom fields support on fulfillments (#4386) and on OrderLines in the modify order page (#4432), dark mode tooltip readability (#4393), and a number of UX improvements like a "Now" button on the date-time picker, better default sort orders, and scrollable configurable operation dropdowns.

On the feature side, product and variant lists now support filtering by facet value (#4415), making it much easier to locate products with specific attributes.

Core fixes include channel-aware productInStock cache keys (#4214), proper persistence of custom fields in updateGlobalSettings (#4343), and correct language fallbacks in FacetService and FacetValueService (#4434).

What's Changed

  • fix(cli): Fix crash when cancelling follow-up feature selection during plugin creation by @michaelbromley in https://github.com/vendurehq/vendure/pull/4371
  • fix(dashboard): Add missing dashboard dependency by @fcFn in https://github.com/vendurehq/vendure/pull/4384
  • fix(dashboard): Return null for nullable non-string field defaults by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4339
  • fix(dashboard): Fix order line discounts showing [object Object] by @gabriellbui in https://github.com/vendurehq/vendure/pull/4378
  • fix(core,elasticsearch-plugin): Include channelId in productInStock cache key by @BibiSebi in https://github.com/vendurehq/vendure/pull/4214
  • fix(core): Persist customFields in updateGlobalSettings mutation by @Ryrahul in https://github.com/vendurehq/vendure/pull/4343
  • fix(dashboard): Multiple small UI fixes by @michaelbromley in https://github.com/vendurehq/vendure/pull/4394
  • fix(dashboard): Keep address visible when editing during order modification by @michaelbromley in https://github.com/vendurehq/vendure/pull/4413
  • feat(dashboard): Add facet value filter to product & variant lists by @michaelbromley in https://github.com/vendurehq/vendure/pull/4415
  • fix: Refresh language selector after saving language by @Ryrahul in https://github.com/vendurehq/vendure/pull/4417
  • fix(create): Use promise-based mysql2 API for database check by @michaelbromley in https://github.com/vendurehq/vendure/pull/4418
  • fix: Add custom fields of fulfillment in dashboard by @Ryrahul in https://github.com/vendurehq/vendure/pull/4386
  • fix(dashboard): Propagate disabled state via React props for all form inputs by @michaelbromley in https://github.com/vendurehq/vendure/pull/4425
  • fix(core): Handle empty sortedAssets in updateEntityAssets by @colinpieper in https://github.com/vendurehq/vendure/pull/4397
  • fix(dashboard): Show custom fields edit button on OrderLine in modify order page by @DeltaSAMP in https://github.com/vendurehq/vendure/pull/4432
  • fix(dashboard): Fix localization issues in Insights Dashboard by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4189
  • fix(dashboard): add scroll to configurable operation dropdown by @Jeffrey-manzl in https://github.com/vendurehq/vendure/pull/4435
  • fix(core): use channel defaultLanguageCode as translation fallback in FacetService and FacetValueService by @mr-mpage in https://github.com/vendurehq/vendure/pull/4434

New Contributors

  • @fcFn made their first contribution in https://github.com/vendurehq/vendure/pull/4384
  • @Jeffrey-manzl made their first contribution in https://github.com/vendurehq/vendure/pull/4435
  • @mr-mpage made their first contribution in https://github.com/vendurehq/vendure/pull/4434

Full Changelog: https://github.com/vendurehq/vendure/compare/v3.5.4...v3.5.5

v3.5.4 Bug fix
Notable features
  • Added Playwright end‑to‑end test suite for the dashboard
  • Swahili (sw) translation added to admin UI
Full changelog

Release Highlights

Dashboard Fixes

A solid batch of fixes for the new React dashboard this release:

  • List relation custom fields now save correctly — Previously, list-type relation custom fields weren't being persisted properly. (#4206)
  • FacetValueInput passes native arrays — The onChange handler now correctly passes native arrays rather than wrapped values. (#4209)
  • ESM path alias resolution — Extension path aliases are now resolved relative to the source file location, fixing issues with dashboard extensions that use custom path mappings. (#4323)
  • Required args validation in ConfigurableOperationInput — Configurable operations (e.g. promotions, shipping calculators) now correctly validate required arguments before submission. (#4202)
  • Order detail refreshes after mutations — The order entity and history timeline now refresh correctly after all mutations, preventing stale data display. (#4338)
  • Missing translations & CI check — Added missing translation keys and a CI script to catch gaps going forward. (#4207)

Core Fixes

  • Promotion side effects now run before OrderLine save — Fixes an issue where in-memory changes made by promotion side effects (e.g. onActivate/onDeactivate modifying custom fields) were not being persisted. The side effects are now executed before the OrderLine save in both the applyPriceAdjustments and modifyOrder code paths. (#4350)
  • Entity events now emit the post-update entityVendureEntityEvent for "updated" events now correctly includes the entity state after the update, rather than the pre-update state. (#4352)
  • Channel-aware tax zone cache keys — Active tax zone lookups are now cached per-channel, fixing incorrect tax calculations when operating across multiple channels with different tax configurations. (#4329)

Create (Scaffolding)

  • Added ts-node to devDependencies — New projects scaffolded with @vendure/create now include ts-node, which was previously missing and caused errors when running migration scripts. (#4212)
  • Explicit localhost API host in Vite config — The storefront Vite template now uses an explicit localhost host for the API proxy, fixing connectivity issues on some systems. (#4349)

Other Improvements

  • Dashboard Playwright e2e test suite — A new end-to-end test suite using Playwright has been added for the dashboard, laying the groundwork for automated UI regression testing. (#4355)
  • GraphiQL transparent background — The embedded GraphiQL plugin now uses a transparent background, making it blend properly with the dashboard theme. (#4205)
  • Swahili translation — Added Swahili (sw) as a new admin UI language. (#4217)
  • Documentation overhaul — Major rework of the core-concepts docs with new pages, sidebar reorganisation, SEO metadata, and restored code examples. (#4347)

What's Changed

  • fix(ci): Correct CI Bot secret names in CLA workflow by @dlhck in https://github.com/vendurehq/vendure/pull/4211
  • fix(dashboard): Pass native arrays from FacetValueInput onChange by @jantokic in https://github.com/vendurehq/vendure/pull/4209
  • fix(graphiql-plugin): Make embedded mode background transparent by @dlhck in https://github.com/vendurehq/vendure/pull/4205
  • chore: Deprecate community plugins by @michaelbromley in https://github.com/vendurehq/vendure/pull/4215
  • ci: Add workflow to auto-generate docs on PR changes by @michaelbromley in https://github.com/vendurehq/vendure/pull/4216
  • ci: Add AI-generated commit messages to docs workflow by @michaelbromley in https://github.com/vendurehq/vendure/pull/4219
  • fix(dashboard): Fix list relation custom fields not saving correctly by @gabriellbui in https://github.com/vendurehq/vendure/pull/4206
  • fix(create): Add ts-node to scaffolded project devDependencies by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4212
  • chore(admin-ui): Add Swahili translation by @barakamwakisha in https://github.com/vendurehq/vendure/pull/4217
  • fix(dashboard): Resolve ESM path aliases relative to source file location by @biggamesmallworld in https://github.com/vendurehq/vendure/pull/4323
  • fix(dashboard): Add missing translations and CI check script by @grolmus in https://github.com/vendurehq/vendure/pull/4207
  • fix(dashboard): Validate required args in ConfigurableOperationInput by @grolmus in https://github.com/vendurehq/vendure/pull/4202
  • docs: Overhaul core-concepts, new pages, sidebar reorg, SEO metadata, restored code examples by @dlhck in https://github.com/vendurehq/vendure/pull/4347
  • fix(create): Use explicit localhost API host in vite config template by @dlhck in https://github.com/vendurehq/vendure/pull/4349
  • fix(core): Emit post-update entity in VendureEntityEvent for updated events by @michaelbromley in https://github.com/vendurehq/vendure/pull/4352
  • feat(dashboard): Add Playwright e2e test suite by @michaelbromley in https://github.com/vendurehq/vendure/pull/4355
  • ci: Optimize Build & Test workflow by @michaelbromley in https://github.com/vendurehq/vendure/pull/4357
  • fix(core): Use channel-aware cache keys for active tax zone by @oliverstreissi in https://github.com/vendurehq/vendure/pull/4329
  • fix(dashboard): Refresh order entity and history after all mutations by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4338
  • fix(core): Run promotion side effects before OrderLine save by @DeltaSAMP in https://github.com/vendurehq/vendure/pull/4350
  • fix(create): Fix welcome message on create by @michaelbromley in https://github.com/vendurehq/vendure/pull/4363

Full Changelog: https://github.com/vendurehq/vendure/compare/v3.5.3...v3.5.4

v3.5.3 Security relevant
Security fixes
  • CVE-2026-25050 — Timing attack vulnerability patched in NativeAuthenticationStrategy, preventing account enumeration by normalizing login response times.
Notable features
  • Refund & Cancel Order Dialog with line item selection and payment allocation
  • Sub-collection pagination for large collection trees
  • Auth methods displayed on user profile page
Full changelog

Highlights

Security Fix

  • Timing attack vulnerability patched - The NativeAuthenticationStrategy had a timing discrepancy that could allow attackers to enumerate valid email addresses by measuring login response times. All authentication attempts now take consistent time, preventing account enumeration attacks. Thanks to Christbowel for the responsible disclosure.

Performance

  • Collections query N+1 fix - Added a new productVariantCount field that uses a simple count query instead of loading all variants just to get totals. Massively reduces database load when listing collections via the Dashboard

Dashboard Compilation

  • Issues with compilation of the Dashboard were traced back to the use of the SWC compiler, which often conflicted with other dependencies in real projects. We moved to a different compiler now which should handle the issues people have been running into.

Dashboard New Features

  • Refund & Cancel Order Dialog - The Dashboard now has a proper refund workflow with line item selection, quantity inputs, payment allocation across multiple payments, and configurable refund reasons.
  • Sub-collection pagination - Large collection trees are now paginated for better performance and UX.
  • Auth methods on profile page - Users can now see their linked authentication methods (native, external providers, etc.) on their profile.
  • Customer search by phone - Customer list now filters by phone number as well as name/email.
  • Dynamic schema-driven languages/currencies - Dashboard language and currency selectors are now driven by your server schema.

Notable Fixes

  • Promotion usage counting - Seller orders are now excluded when counting promotion usage, fixing incorrect limits in multi-vendor setups.
  • SubscribableJob.updates() - Fixed a bug where job.updates() would complete after a single emission instead of streaming updates until the job finished. This affected anyone using lastValueFrom(job.updates()) patterns.
  • Custom fields on ProductVariantPrice - Both persistence and display in the Dashboard are now working correctly.
  • Localized custom fields - localeString and localeText custom fields on translatable entities now persist properly.
  • ChangeChannelEvent - Now correctly publishes with the new channel IDs instead of the old ones.
  • pnpm and Bun support - Dashboard plugin detection now works properly with pnpm and Bun package managers.

What's Changed

  • feat(dashboard): Provide entity object to draft-order-detail Page component by @lucatk in https://github.com/vendurehq/vendure/pull/4073
  • fix(dashboard): Prevent NaN or empty values in Latest Orders table w… by @raidsobhi in https://github.com/vendurehq/vendure/pull/4092
  • fix(dashboard): Re-sync channel token when activeChannelId persists but token is cleared by @niko91i in https://github.com/vendurehq/vendure/pull/4094
  • fix(dashboard): Fix incorrect currency being displayed in dashboard u… by @raidsobhi in https://github.com/vendurehq/vendure/pull/4090
  • fix(dashboard): Channel switcher not scrollable if list exceeds screen height by @lucatk in https://github.com/vendurehq/vendure/pull/4075
  • fix(dashboard): hide "Add channel" button for users without CreateChannel permission by @niko91i in https://github.com/vendurehq/vendure/pull/4097
  • fix(dashboard): Fix compilation issues caused by SWC version issues by @michaelbromley in https://github.com/vendurehq/vendure/pull/4105
  • feat(core): Expand userHasPermissions docstring; Add new userHasAllPermissions method by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4107
  • fix(dashboard): Fix struct custom fields not rendering options or custom components by @michaelbromley in https://github.com/vendurehq/vendure/pull/4115
  • fix(core): Use previously unused relations filter in findByCustomerId by @DeltaSAMP in https://github.com/vendurehq/vendure/pull/4118
  • feat(dashboard): Use dynamic schema-driven languages and currencies by @TheHypnoo in https://github.com/vendurehq/vendure/pull/4111
  • fix(core): Fix SubscribableJob.updates() completing after single emission by @michaelbromley in https://github.com/vendurehq/vendure/pull/4120
  • feat(create): Set api url to auto for newly created projects by @martijnvdbrug in https://github.com/vendurehq/vendure/pull/4102
  • chore: Improve dashboard test reliability in publish workflow by @michaelbromley in https://github.com/vendurehq/vendure/pull/4122
  • docs: add warning to distinguish custom field extension vs detail input field extension by @BibiSebi in https://github.com/vendurehq/vendure/pull/4123
  • fix(create,docs): add useDefineForClassFields to fix ES2022 by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4116
  • chore: Speed up publish_and_install workflow by @michaelbromley in https://github.com/vendurehq/vendure/pull/4127
  • fix(dashboard): Dashboard plugin detection with pnpm by @oliverstreissi in https://github.com/vendurehq/vendure/pull/4126
  • fix(core): Respect publishConfig.directory in npm publish workflow by @michaelbromley in https://github.com/vendurehq/vendure/pull/4131
  • fix(dashboard): Bump @tanstack/react-router to fix ID param error by @jantokic in https://github.com/vendurehq/vendure/pull/4153
  • fix(dashboard): Hide bulk action bar when no selected items are visible by @jantokic in https://github.com/vendurehq/vendure/pull/4151
  • Fix(Mollie): allow overriding immediateCapture from the plugin level by @martijnvdbrug in https://github.com/vendurehq/vendure/pull/4142
  • fix(dashboard): Resolve tsconfig path aliases in ESM mode by @michaelbromley in https://github.com/vendurehq/vendure/pull/4134
  • feat: Implement productVariantCount in collections query by @biggamesmallworld in https://github.com/vendurehq/vendure/pull/4132
  • docs: Fix typo in plugins documentation by @aidenBarrett96 in https://github.com/vendurehq/vendure/pull/4145
  • fix(dashboard): Register text-form-input component by @BibiSebi in https://github.com/vendurehq/vendure/pull/4149
  • fix(dashboard): Preserve string arg values without JSON parsing in form inputs by @gabriellbui in https://github.com/vendurehq/vendure/pull/4156
  • fix(dashboard): Fix entity creation when using a non default language by @tbouliere-datasolution in https://github.com/vendurehq/vendure/pull/4157
  • chore: Add Claude Code rules for dashboard i18n by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4166
  • fix(dashboard): Fix gross price display under price includes tax by @Qingbao in https://github.com/vendurehq/vendure/pull/4138
  • fix(dashboard): Fix usePaginatedList context duplication in extensions by @michaelbromley in https://github.com/vendurehq/vendure/pull/4164
  • feat(dashboard): Add pagination for sub-collections in collection list by @biggamesmallworld in https://github.com/vendurehq/vendure/pull/4154
  • fix(dashboard): Fix displaying HistoryEntry for CustomerEmailUpdateComponent by @SiebelsTim in https://github.com/vendurehq/vendure/pull/4167
  • fix(dashboard): Fallback to default input when custom form component not found by @DeltaSAMP in https://github.com/vendurehq/vendure/pull/4168
  • feat(docs): Migrate documentation to @vendure/docs package by @dlhck in https://github.com/vendurehq/vendure/pull/4124
  • fix(core): Correctly publish ChangeChannelEvent with new channel IDs. by @Draykee in https://github.com/vendurehq/vendure/pull/4176
  • feat(dashboard): Add disabled option to exclude columns in ListPage by @BibiSebi in https://github.com/vendurehq/vendure/pull/4170
  • fix(dashboard): Show all items in the order details page, clean up fu… by @oidt in https://github.com/vendurehq/vendure/pull/4160
  • feat(dashboard): Add refundOrder and cancelOrder GraphQL mutations by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4130
  • fix: Sync package-lock.json with package.json by @HouseinIsProgramming in https://github.com/vendurehq/vendure/pull/4178
  • feat(dashboard): Display authentication methods on profile page by @dlhck in https://github.com/vendurehq/vendure/pull/4179
  • fix(dashboard): Clarify draft order completion UX and add ar translations by @mohamed7-dev in https://github.com/vendurehq/vendure/pull/4163
  • fix(dashboard): Collection contents not showing after saving filters by @gabriellbui in https://github.com/vendurehq/vendure/pull/4128
  • feat(dashboard): Add phone number field to customer list query and search functionality by @TheHypnoo in https://github.com/vendurehq/vendure/pull/4100
  • fix(dashboard): Transform Lingui macros in third-party npm packages by @michaelbromley in https://github.com/vendurehq/vendure/pull/4182
  • fix(dashboard): Support Bun package manager in plugin discovery by @oliverstreissi in https://github.com/vendurehq/vendure/pull/4183
  • fix(core): Persist custom fields when creating new ProductVariantPrice by @michaelbromley in https://github.com/vendurehq/vendure/pull/4184
  • fix(dashboard): Persist localeString/localeText custom fields on translatable entities by @michaelbromley in https://github.com/vendurehq/vendure/pull/4185
  • fix(core): Exclude seller orders when counting promotion usage by @twlite in https://github.com/vendurehq/vendure/pull/4070
  • fix(dashboard): Boolean fields in DetailPage now show correct value by @oliverstreissi in https://github.com/vendurehq/vendure/pull/4186
  • fix(dashboard): Display custom fields on product variant prices by @mehringer68 in https://github.com/vendurehq/vendure/pull/4180

New Contributors

  • @lucatk made their first contribution in https://github.com/vendurehq/vendure/pull/4073
  • @raidsobhi made their first contribution in https://github.com/vendurehq/vendure/pull/4092
  • @niko91i made their first contribution in https://github.com/vendurehq/vendure/pull/4094
  • @TheHypnoo made their first contribution in https://github.com/vendurehq/vendure/pull/4111
  • @aidenBarrett96 made their first contribution in https://github.com/vendurehq/vendure/pull/4145
  • @tbouliere-datasolution made their first contribution in https://github.com/vendurehq/vendure/pull/4157
  • @Qingbao made their first contribution in https://github.com/vendurehq/vendure/pull/4138
  • @mehringer68 made their first contribution in https://github.com/vendurehq/vendure/pull/4180

Full Changelog: https://github.com/vendurehq/vendure/compare/v3.5.2...v3.5.3

Beta — feedback welcome: [email protected]