docs/docs/guides/core-concepts/pricing/index.mdx
Vendure uses a multi-stage pipeline to determine the price a customer actually pays. Rather than storing a single "final" price, the system starts with a base price and transforms it step-by-step through strategies, promotions, and tax calculations. This makes it possible to support complex scenarios like channel-specific pricing, dynamic discounts, and tax-inclusive or tax-exclusive display.
When an item is added to an order, Vendure resolves its price through the following stages:
ProductVariant has one or more ProductVariantPrice records, scoped by channel and currency.ProductVariantPrice to use when multiple prices exist for the active channel and currency.The result of this pipeline is exposed in the GraphQL API as a pair of fields on every taxable price: a base field and a WithTax field. For example, an OrderLine exposes linePrice and linePriceWithTax, and the Order itself exposes subTotal / subTotalWithTax, total / totalWithTax, and so on.
Because ProductVariantPrice records are scoped to a specific channel and currency, the same product variant can have entirely different prices in different channels. This is essential for multi-region or multi-vendor setups where each storefront operates with its own currency and pricing structure.
A single variant might have a price of $30 USD in the US channel and 25 GBP in the UK channel. If a channel supports multiple currencies, the variant can even have more than one price within that channel.
price vs priceWithTax conventionThroughout the Vendure GraphQL APIs, monetary values always come in pairs:
price — The amount without tax (or the tax-inclusive amount if the channel is configured for tax-inclusive pricing, in which case tax has been back-calculated).priceWithTax — The amount with tax included.This convention applies to individual line items, order subtotals, shipping costs, and the order total. Your storefront can choose which value to display based on local regulations and conventions.
:::info All monetary values in Vendure are stored as integers in the smallest currency unit (e.g., cents for USD). See Money & Currency for details on how Vendure handles monetary arithmetic. :::
After the base price is resolved, Vendure applies any qualifying promotions. Promotions never modify the base price directly. Instead, they add adjustments to the order or order line, which are tracked separately. This means the original price is always preserved, and discounts can be clearly itemized for the customer.
There are two levels of adjustment:
Both types are stored alongside the order and are visible in the API, so your storefront can show the customer exactly which discounts were applied and how much they saved.
The pricing pipeline is designed to be customized at each stage. The two most common extension points are:
Both strategies are configured at the server level and apply globally. For details on implementing custom strategies, see the TypeScript API reference.