A configurable, framework-agnostic pricing engine for any business domain.
Define your pricing rules in a simple JSON config — the engine does the math.
Every business has pricing logic. Most teams build it from scratch, tightly coupled to their application. This engine extracts that logic into a reusable, testable, configurable module.
Born from real-world experience building ERP pricing systems — area-based calculations, tiered rates, minimum charges, discounts. Abstracted to work across any domain: manufacturing, logistics, SaaS, e-commerce.
The npm ecosystem has plenty of billing and payment platforms (subscriptions, invoicing, tax), but few dedicated, standalone pricing engines — especially ones that handle physical dimensions like area, length, volume or weight. This library focuses purely on the pricing calculation: typed, validated, framework-agnostic, with no dependency on any payment provider.
- Config-driven — define pricing rules in JSON, no hardcoding
- Multiple pricing strategies — area, linear, volume, weight, time, piece and flat
- Discounts & surcharges — percentage and fixed adjustments, applied as a cascade
- Minimum charge — guaranteed price floor per item
- Per-strategy validation — each strategy's required dimensions are checked with descriptive errors
- Framework-agnostic — pure TypeScript, runs anywhere
- Minimal dependencies — only Zod for validation
- 100% test coverage — tested with Vitest
- TypeScript-first — full type safety, great DX
npm install open-pricing-engineimport { PricingEngine } from 'open-pricing-engine';
const engine = new PricingEngine({
rules: [
{
name: 'flat-surface',
type: 'area',
unitPrice: 12.5,
unit: 'm2',
minCharge: 25.0,
},
],
});
const result = engine.calculate({
rule: 'flat-surface',
dimensions: { width: 2.0, height: 1.5 },
quantity: 10,
});
// Result:
// {
// rule: 'flat-surface',
// measure: 3.0,
// unitPrice: 12.50,
// subtotal: 37.50, // 3.0 × 12.50
// adjustments: [], // no adjustments configured
// adjusted: 37.50, // subtotal after adjustments
// quantity: 10,
// total: 375.00 // 37.50 × 10
// }The calculation type is chosen per rule via the type field. Each strategy
turns the input dimensions into a billable measure, then
subtotal = measure × unitPrice.
type |
Required dimensions | measure |
Example unit |
|---|---|---|---|
area |
width, height |
width × height |
m² |
linear |
length |
length |
m |
volume |
width, height, depth |
width × height × depth |
m³ |
weight |
weight |
weight |
kg |
time |
hours |
hours |
h |
piece |
— | 1 (per-unit item) |
pc |
flat |
— | 1 (fixed service fee) |
job |
const engine = new PricingEngine({
rules: [
{ name: 'cable', type: 'linear', unitPrice: 3, unit: 'm' },
{ name: 'tank', type: 'volume', unitPrice: 8, unit: 'm3' },
{ name: 'setup', type: 'flat', unitPrice: 50, unit: 'job' },
],
});
engine.calculate({ rule: 'cable', dimensions: { length: 4 }, quantity: 1 }).measure; // 4
engine.calculate({ rule: 'tank', dimensions: { width: 2, height: 2, depth: 2 }, quantity: 1 })
.measure; // 8
engine.calculate({ rule: 'setup', dimensions: {}, quantity: 1 }).measure; // 1Missing required dimensions throw a descriptive validation error (for example,
a volume rule without depth).
The engine works for any business where price depends on item dimensions:
- Metal coating & powder painting (price per m²)
- CNC machining, laser cutting (price per area)
- Glass, flooring, fabric (price per m² with minimum charge)
Future versions will support tiered pricing, discounts, and custom formulas — see Roadmap.
| Version | Scope | Status |
|---|---|---|
| v0.1 | Area-based pricing, JSON config, minimum charge | Released |
| v0.2 | Discounts & surcharges (%, absolute) | Released |
| v0.3 | Calculation strategies (area, linear, volume, weight, etc.) | Released |
| v0.4 | Price list versioning, effective dates | Planned |
| v0.5 | Tiered pricing (volume & graduated) | Planned |
| v0.6 | REST API wrapper (Fastify) | Planned |
| v0.7 | Interactive playground (React) | Planned |
| v1.0 | Plugin system for custom formulas | Planned |
open-pricing-engine/
├── packages/
│ ├── core/ — pricing logic (npm package)
│ ├── api/ — REST API wrapper (planned)
│ └── playground/ — interactive demo (planned)
├── docs/ — architecture decisions
└── .github/workflows/ — CI/CD
# Prerequisites: Node.js 22+, pnpm 10+
pnpm install # Install dependencies
pnpm test # Run tests
pnpm typecheck # Type-check
pnpm build # Build
pnpm format # Format codeContributions are welcome! Please open an issue first to discuss what you'd like to change.
- Fork the repository
- Create your branch (
git checkout -b feat/my-feature) - Commit using conventional commits
- Open a Pull Request