npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

prices-as-code

v3.6.0

Published

Prices as Code (PaC) - Define your product pricing schemas with type-safe definitions

Readme

Prices as Code (PaC)

Define your product pricing schemas with type-safe definitions and synchronize them across multiple providers.

🚀 Features

  • Type-Safe: Use TypeScript and Zod schemas to define your pricing models with full type safety
  • Declarative: Define your products and prices in code, sync them to providers
  • Scaffolding: Generate template pricing structures to quickly get started
  • Bidirectional: Use Push mode to sync local configs to providers, or Pull mode to generate configs from existing providers
  • Idempotent: Run it multiple times, only changes what's needed
  • Push Model: Push your config to different environments without ID conflicts
  • Pull Model: Generate config files from existing provider data to onboard existing customers
  • Metadata Support: Add custom metadata to your products and prices
  • YAML or TypeScript: Define your pricing in either YAML or TypeScript format
  • Extensible: Easily add support for your own billing providers

Installation

npm install prices-as-code

Quick Start

1. Create a pricing configuration file (pricing.ts)

import { Config } from "prices-as-code";

const config: Config = {
  products: [
    {
      provider: "stripe",
      name: "Basic Plan",
      description: "For individuals and small teams",
      features: ["5 projects", "10GB storage", "Email support"],
      highlight: false,
      metadata: {
        displayOrder: 1,
      },
    },
    {
      provider: "stripe",
      name: "Pro Plan",
      description: "For growing businesses",
      features: ["Unlimited projects", "100GB storage", "Priority support"],
      highlight: true,
      metadata: {
        displayOrder: 2,
      },
    },
  ],
  prices: [
    {
      provider: "stripe",
      name: "Basic Monthly",
      nickname: "Basic Monthly",
      unitAmount: 999, // $9.99
      currency: "usd",
      type: "recurring",
      recurring: {
        interval: "month",
        intervalCount: 1,
      },
      productKey: "basic_plan",
      metadata: {
        displayName: "Basic Monthly",
      },
    },
    {
      provider: "stripe",
      name: "Pro Monthly",
      nickname: "Pro Monthly",
      unitAmount: 1999, // $19.99
      currency: "usd",
      type: "recurring",
      recurring: {
        interval: "month",
        intervalCount: 1,
      },
      productKey: "pro_plan",
      metadata: {
        displayName: "Pro Monthly",
      },
    },
  ],
};

export default config;

2. Set up environment variables

# .env file
STRIPE_SECRET_KEY=sk_test_...

3. Run the synchronization

npx prices-as-code pricing.ts

CLI Options

prices-as-code [command] [configPath] [options]

Commands:
  sync             Synchronize your pricing schema with provider (default)
  pull             Pull pricing from provider into a local config file
  generate         Generate a template pricing structure

Options:
  --env=<path>          Path to .env file
  --stripe-key=<key>    Stripe API key
  --write-back          Write provider IDs back to config file (only for sync)
  --format=<format>     Output format for 'pull' and 'generate' commands (yaml, json, ts)
  
Generate Options:
  --tiers=<tiers>       Comma-separated list of product tiers (default: basic,pro,enterprise)
  --currency=<cur>      ISO currency code (default: usd)
  --intervals=<int>     Comma-separated list of intervals (default: month,year)
  --no-metadata         Don't include metadata in generated file
  --no-features         Don't include feature lists in generated products

Examples

# Sync local pricing to provider (Push mode)
npx prices-as-code pricing.ts

# Pull provider pricing to local file (Pull mode)
npx prices-as-code pull pricing.yml

# Pull provider pricing with specific format
npx prices-as-code pull --format=ts pricing.ts

# Generate a template pricing structure
npx prices-as-code generate pricing.yml

# Generate with custom tiers and currency
npx prices-as-code generate --tiers=free,basic,pro --currency=eur pricing.yml

Supported Providers

Stripe

The Stripe provider allows you to sync products and prices to your Stripe account.

Required environment variables:

  • STRIPE_SECRET_KEY: Your Stripe secret key
  • STRIPE_API_VERSION (optional): Stripe API version to use

Programmatic Usage

Push Mode (Sync)

import { pac } from "prices-as-code";

async function syncPricing() {
  try {
    const result = await pac({
      configPath: "./pricing.ts",
      providers: [
        {
          provider: "stripe",
          options: {
            secretKey: process.env.STRIPE_SECRET_KEY,
            apiVersion: "2025-02-24",
          },
        },
      ],
      // Set to true to write IDs back to config file (legacy behavior)
      // Default is false (push mode - no writes to config file)
      writeBack: false,
    });

    console.log("Sync result:", result);
  } catch (error) {
    console.error("Sync failed:", error);
  }
}

syncPricing();

Pull Mode (Import)

import { pac } from "prices-as-code";

async function pullPricing() {
  try {
    const result = await pac.pull({
      configPath: "./pricing.yml", // Output file path
      providers: [
        {
          provider: "stripe",
          options: {
            secretKey: process.env.STRIPE_SECRET_KEY,
          },
        },
      ],
      format: "yaml", // 'yaml', 'json', or 'ts'
    });

    console.log("Pull complete:", result);
  } catch (error) {
    console.error("Pull failed:", error);
  }
}

pullPricing();

Generate Mode (Scaffolding)

import { pac } from "prices-as-code";

async function generatePricing() {
  try {
    const result = await pac.generate({
      configPath: "./pricing.yml", // Output file path
      format: "yaml", // 'yaml', 'json', or 'ts'
      provider: "stripe",
      productTiers: ["basic", "pro", "enterprise"], // Custom tiers
      intervals: ["month", "year"], // Billing intervals
      currency: "usd",
      includeMetadata: true,
      includeFeatures: true
    });

    console.log("Template generated:", result);
  } catch (error) {
    console.error("Generation failed:", error);
  }
}

generatePricing();

Adding Your Own Provider

You can extend the library with your own providers by implementing the ProviderClient interface:

import { ProviderClient, Product, Price } from "prices-as-code";

export class MyCustomProvider implements ProviderClient {
  constructor(options: any) {
    // Initialize your provider client
  }

  // Push mode methods - required
  async syncProducts(products: Product[]): Promise<Product[]> {
    // Implement product synchronization
    return products;
  }

  async syncPrices(prices: Price[]): Promise<Price[]> {
    // Implement price synchronization
    return prices;
  }

  // Pull mode methods - required
  async fetchProducts(): Promise<Product[]> {
    // Implement product fetching from provider
    return [];
  }

  async fetchPrices(): Promise<Price[]> {
    // Implement price fetching from provider
    return [];
  }
}

📖 Documentation

Visit our documentation website for comprehensive guides and API reference.

Guides

API Reference

🧩 Why Prices as Code?

Managing pricing configurations across multiple systems is challenging. Prices as Code provides:

  1. Single Source of Truth: Define your pricing once, deploy everywhere
  2. Type Safety: Catch errors before they happen with TypeScript validation
  3. Version Control: Track pricing changes alongside your codebase
  4. CI/CD Integration: Automate pricing updates as part of your deployment pipeline

📄 License

MIT