Vendure Core v3.7: Developer Experience, Dashboard Improvements, and Security Hardening

Developer Experience
In this release, we're introducing a number of features to make your day-to-day development experience smoother, faster, and more productive.
A smoother CLI
v3.7 adds three CLI commands for running a Vendure project (#4774). Previously, projects relied on their own scripts - ts-node, concurrently, and separate steps to build the dashboard and start the compiled output. These commands replace that setup:
vendure devruns the server, worker, and dashboard with auto-reload. It watches backend files, reloads on.envchanges, reloads dashboard extensions, and supports Node inspector flags. Pass--no-reloadto disable watching.vendure buildcompiles the server, worker, and dashboard for production. It supports tsconfig discovery, a separate worker tsconfig,--clean,--watch, and--verbose.vendure startruns the compiled server and worker, with prefixed output from each process and coordinated shutdown.
The add, migrate, schema, and codemod commands now fail fast instead of waiting on a prompt when run in a non-interactive environment such as CI or an AI coding agent.
vendure doctor
The new vendure doctor command runs diagnostic checks against a project and produces a report (#4777). It is useful for debugging a problematic project, verifying an upgrade, setting up a new machine, or as a check in CI.
It runs five checks by default:
- Project - verifies the project structure, config file discovery, package manager detection, and lockfile consistency.
- Dependencies - checks for matching versions across
@vendure/*packages, no duplicate copies of singletons such asgraphql,typeorm, and@nestjs/core, and that a database driver is installed. - Config - loads and validates your config via
preBootstrapConfig(), including custom fields and entities, and checks plugin compatibility ranges. - Schema - confirms the Admin API and Shop API GraphQL schemas build successfully.
- Database - tests database connectivity using read-only overrides, and warns if
synchronize: trueis enabled.
A separate Production check runs when you pass --profile production. Each check reports pass, warn, fail, or skip. You can run specific checks with --check, output JSON with --format json, and treat warnings as failures with --strict for use in CI.
AI-assisted development
New projects created with @vendure/create now contain an AGENTS.md file (#4850). This is the project context file that AI coding agents read to understand how a codebase is structured and what conventions it follows. The generated file describes the Vendure project layout, the main commands, and patterns to follow when adding plugins and dashboard extensions.
We also now provide a set of skills which you can use with your AI coding agent via the cross-agent skills CLI tool.
A better getting-started experience
@vendure/create now supports bun, pnpm, and yarn in addition to npm when scaffolding a new project (#4877).
We detect the desired package manager based on how you invoke it - e.g. running bunx @vendure/create my-shop will scaffold a project with Bun, while pnpm dlx @vendure/create my-shop will use pnpm.
Pre-bundled dashboard (experimental)
In development, the dashboard ships as TypeScript source, so your project's Vite dev server serves it as thousands of individual modules. On a cold load that adds up, and in some cases it crashed the browser tab during dashboard extension development.
v3.7 adds an opt-in mode that ships the dashboard as a pre-built ESM bundle instead. Enable it by setting useExperimentalBundle: true on vendureDashboardPlugin in your Vite config (#4719).
Measured on a fresh @vendure/create project with one dashboard extension, on a cold load of /dashboard/:
| Metric | Source mode (default) | Bundle mode | Change |
|---|---|---|---|
| Network requests | 3,047 | 39 | −98.7% |
| DOMContentLoaded | 897 ms | ~370 ms | −59% |
| JS heap used | 168 MB | ~95 MB | −43% |
The default is unchanged. This mode is opt-in and experimental while we test it across real-world projects, so we'd like your feedback before we make it the default.
Once you upgrade you can try it out in your own project by adding the option to your Vite config:
Dashboard Improvements
Custom React providers
Dashboard extensions can now register custom React providers (#4600). You pass them to defineDashboardExtension(), and they are rendered around the dashboard at either the app or layout level, with explicit ordering. This lets an extension wrap the dashboard in any context it needs - a feature-flag provider, an error boundary, or a theme provider for the extension's own components.
User stylesheets
vendureDashboardPlugin has a new additionalStylesheets option that injects your own CSS file (or files) into the dashboard (#4765, #4905). Previously you had to write a custom Vite transform plugin to splice an @import into the dashboard's stylesheet. Now you pass the paths directly:
Each file is added as an @import immediately after Tailwind's import, so your CSS runs through the dashboard's Tailwind v4 pipeline. That means you can use @source, @theme, @apply, @utility, and custom variants inside it - useful for applying your own branding to the dashboard or defining utility classes for your extensions.
Configurable DataTable column defaults
Plugins can now set the default column visibility and order for dashboard data tables via the Plugin Extension API (#4197). For example, if you add a custom field and want it shown as a column by default, or want to hide a column that is normally visible, you can now configure that rather than leaving every user to set it themselves.
And more
- Configurable TanStack Router options (#4862). A new
tanstackRouterPluginOptionsoption onvendureDashboardPluginis merged over the dashboard's router defaults. This allows a wider range of project structures and deployment targets to be supported. - Focal point editor in the asset preview dialog (#4755). You could already set an asset's focal point from the standalone asset detail page, but not from the preview dialog used by product and variant asset galleries. The editor is now available there too.
- New Uzbek translation (#4837) and additional Russian order-action strings (#4838).
Security Hardening
Several recent high-profile supply-chain attacks on the npm ecosystem prompted a wide-ranging review of Vendure's security posture. One part of this was recently covered in our blog post How Vendure keeps Shai-Hulud out of your stack, which details the layered approach we implemented to harden our release pipeline.
Another part of supply-chain security is reducing the number of dependencies you carry. Every dependency is code you run and a maintainer you trust, and most attacks reach you through a package deep in the tree rather than one you installed directly. Two pieces of work in v3.7 reduce that exposure: a dependency audit, and a round of dependency updates to clear known npm audit warnings. Alongside these, we fixed and disclosed a number of reported vulnerabilities, and hardened the default production setup.
A dependency audit
We audited Vendure's entire dependency footprint (#4761), starting from a baseline of around 1,880 unique production packages across the repo. We worked through it using four rules:
- Remove dependencies that are not used.
- Replace dependencies whose job is now done by a Node.js built-in.
- Vendor small, pure-code, zero-dependency packages directly into the codebase.
- Keep non-trivial, security-sensitive, and canonical packages, where reimplementing them would be more dangerous than depending on them.
The results shipped across several PRs:
- Around 145 transitive dependencies removed with no change in behaviour (#4762): dropping
body-parser(never imported), recategorising the mislabelled@types/nodemailerdependency, and replacingnode-fetchandform-datawith the nativefetchandFormDatain Node.js. - A curated telemetry instrumentation set (#4764).
@opentelemetry/auto-instrumentations-nodepulled in 40+ instrumentation packages for databases and frameworks Vendure does not use (Cassandra, Kafka, Mongoose, AWS Lambda, and others). We now ship the eight that match the Vendure stack, and you can opt in to the rest. - Dropping
@nestjs/terminus(#4771), which we used only for types. We replaced its health check with a directSELECT 1and vendored the few types we needed. - Vendoring and native replacements for
graphql-fields,progress, andtcp-port-used(#4768, #4769, #4770).
The audit also records which dependencies we kept and why. Packages such as graphql-upload, cookie-session, and mime-types stay because they are the canonical implementation of a wire spec or a maintained data registry. The reasoning is documented on the audit issue.
Clearing npm audit warnings
We also updated runtime dependencies of the published packages to clear the npm audit warnings that a fresh Vendure install reports (#4906). The main changes are mjml 4 to 5, which removes the unmaintained html-minifier (an unfixed ReDoS advisory) from the email plugin's dependency tree, and nodemailer 6 to 9, along with version-floor bumps for i18next-fs-backend and i18next-http-middleware.
Measured against a fresh @vendure/create install:
npm audit | Before (3.6.4) | After |
|---|---|---|
| Critical | 0 | 0 |
| High | 42 | 9 |
| Moderate | 6 | 5 |
| Total | 48 | 14 |
That is 34 fewer warnings on a fresh install, with high-severity warnings down from 42 to 9. Of the nine that remain, seven are a single multer denial-of-service advisory that reaches us through @nestjs/platform-express. The fix for that is landing upstream in NestJS, and a fresh install will pick it up automatically once it ships.
Reported vulnerabilities
Alongside this release we are publishing a set of security advisories for vulnerabilities that have now been fixed. All of the fixes below are in 3.7.0. Where the fix was also merged to the 3.6.x line, it is available in the latest 3.6.x patch release, so you can take the fix without upgrading to the minor.
| Severity | Vulnerability | Advisory | Fixed in |
|---|---|---|---|
| Critical | External-authentication account takeover: an external/SSO login could be linked to a pre-existing account by email address without verification | GHSA-6j36-r6pr-59x4 | 3.7.0 |
| High | Stored XSS in the dashboard from unsafe HTML-stripping of entity descriptions | GHSA-xhq9-whgq-49j5 | 3.7.0 and latest 3.6.x patch |
| High | Unauthenticated denial of service (ReDoS) via the regex filter on SQLite backends | GHSA-jgm3-qmp2-c4p7 | 3.7.0 and latest 3.6.x patch |
| High | File-upload type bypass: uploads were accepted on the Content-Type header without verifying the file contents | GHSA-88rq-mq4v-frmm | 3.7.0 and latest 3.6.x patch |
| Moderate | Shop API list queries could return non-public entities when filterOperator was set to OR | GHSA-xf65-r35x-wmmv | 3.7.0 and latest 3.6.x patch |
We are grateful to the security researchers who reported these responsibly.
Other security fixes
- Channel scoping on entity updates (#4821).
AssetService.updateandStockLocationService.updatenow scope the lookup by channel, closing a gap where a channel-restricted administrator could modify an entity in another channel.
Refuse the default superadmin password in production
Vendure now refuses to start in production if the superadmin account still uses the default password (#4718). See Breaking Changes below.
New Pluggable Strategies
Behaviour that varies between businesses is exposed in Vendure as a configurable strategy rather than fixed in core. v3.7 adds two new ones. Both ship with a default that matches the existing behaviour, so neither changes anything unless you opt in.
CustomerChannelAssignmentStrategy
By default, when an authenticated customer's request targets a channel they are not yet a member of, Vendure assigns them to that channel. The new CustomerChannelAssignmentStrategy lets you control that assignment (#4863).
The strategy has a single canAssignCustomerToChannel() method. Returning false lets the customer use the channel for that session without becoming a member of it. This is useful in multi-channel or B2B setups where you want customer bases kept strictly separate, or where channel membership is granted by an administrator rather than automatically.
See the CustomerChannelAssignmentStrategy documentation for full details.
OrderLineDiscountDistributionStrategy
When an order-level promotion applies a discount (for example "$50 off the order"), that discount has to be distributed across the individual order lines. The new OrderLineDiscountDistributionStrategy makes the distribution configurable (#4818).
Configure it with the orderOptions.orderLineDiscountDistributionStrategy option. See the OrderLineDiscountDistributionStrategy documentation for full details of when this new strategy
should be used.
Other Notable Features and Fixes
Features
CouponRemovedDuringCheckoutErroradded toAddPaymentToOrderResult(#4683) - handle the case where a coupon becomes invalid mid-checkout.- Pooled SMTP options in the email plugin (#4861).
Fixes worth mentioning
- Exclude draft orders from promotion usage-limit counts (#4854) - draft orders no longer eat into a promotion's usage limit.
- Prevent duplicate-key errors in DefaultSearchPlugin index writes (#4809).
- Seed StockLevel on variant channel assignment (#4864).
- Prevent unbounded i18next preload growth (#4824) - a memory leak fix for long-running servers.
- Only send edited stock levels on variant update (#4834).
- Redirect to list in the Dashboard when a detail entity isn't found in the active channel (#4874).
Breaking Changes
v3.7 is a minor release, but some dependency updates and security hardening have introduced breaking changes in very specific cases that may require action when upgrading.
Coupon codes are now compared case-insensitively (#4419), bringing Vendure in line with other commerce platforms. This only affects you if you've been using different-case versions of the same code to refer to distinct promotions - in which case those will now collide.
The default superadmin password is refused in production (#4718). If your production environment still uses the default superadmin password, Vendure will no longer start. You must change the superadmin password before upgrading.
External authentication now requires a verified email to link to an existing account. As part of the fix for the external-authentication account takeover advisory above, an external login is only linked to a pre-existing account when the external email is verified. If you have a custom AuthenticationStrategy, it must set verified: true on the returned user data for provider-verified emails; otherwise the link is refused. Creating new accounts is unchanged.
Thank You
v3.7 includes direct contributions from 27 community members. From significant features to translations, bug fixes, and documentation improvements, every contribution matters.
Whether you submitted a PR, reported an issue, helped someone in Discord, or just gave us feedback on what to build next, thank you.
Share this article
Worth reading, once a month
Product updates, customer stories, and engineering thinking, delivered monthly.








