# Overview

Pricing management lets your team instantly update and experiment on pricing, without redeploying your app.

## Problem

Without pricing management:

* **Complex updates** — Changing pricing requires coordinated code changes across the frontend, backend, and marketing site. Rolling back changes is even harder.
* **Engineering bottlenecks** — Product and marketing depend on engineering for every pricing change.
* **Limited experimentation** — It's difficult to test and iterate, leading to suboptimal pricing and lost revenue.

## Solution

Define your pricing in Hypertune as flags instead of hardcoded values:

```graphql
type Root {
  pricing: Pricing!
}

type Pricing {
  stripePrices(plan: Plan!): [StripePrice!]!
  planContent(plan: Plan!): PlanContent!
  planFeatures: [PlanFeature!]!
  planOrdering: [Plan!]!
}

enum Plan { free, pro, enterprise }

type StripePrice {
  id: String!
  type: StripePriceType!
}

enum StripePriceType { flatFee, perSeat }

type PlanContent {
  name: String!
  description: String!
  features: [String!]!
}

type PlanFeature {
  name: String!
  value(plan: Plan!): PlanFeatureValue!
}

type PlanFeatureValue {
  isIncluded: Boolean!
  text: String!
}
```

Then reference it in your code:

{% code title="api/upgrade/route.ts" %}

```typescript
import { waitUntil } from '@vercel/functions'
import { NextResponse } from 'next/server'
import getHypertune from '@/lib/getHypertune'
import getStripe from '@/lib/getStripe'
import getTeamSize from '@/lib/getTeamSize'

export const runtime = 'edge'

export async function POST(request: Request) {
  const hypertune = await getHypertune({ isRouteHandler: true })

  const stripePrices = hypertune
    .pricing()
    .stripePrices({ args: { plan: 'pro' } })
    .map((price) => price.get())

  const teamSize = getTeamSize()

  const lineItems = stripePrices.map((price) => ({
    price: price.id,
    quantity: price.type === 'perSeat' ? teamSize : 1,
  }))

  const stripe = getStripe()

  const baseUrl = new URL(request.url).origin

  const session = await stripe.checkout.sessions.create({
    mode: 'subscription',
    line_items: lineItems,
    success_url: `${baseUrl}/success`,
    cancel_url: `${baseUrl}/cancel`,
  })

  waitUntil(hypertune.flushLogs())

  return NextResponse.json({
    sessionUrl: session.url,
    sessionId: session.id,
  })
}
```

{% endcode %}

{% code title="components/Pricing.tsx" %}

```tsx
import FeaturesTable from './FeaturesTable'
import PlansTable from './PlansTable'
import getHypertune from '@/lib/getHypertune'

export default async function Pricing() {
  const hypertune = await getHypertune()
  const pricing = hypertune.pricing()

  return (
    <div className="pricing">
      <h2>Pricing</h2>
      <PlansTable pricing={pricing} />
      <FeaturesTable pricing={pricing} />
    </div>
  )
}
```

{% endcode %}

{% code title="components/PlansTable.tsx" %}

```tsx
import {
  type PricingNode,
  type PlanContentNode,
} from '@/generated/hypertune'

export default function PlansTable({
  pricing,
}: {
  pricing: PricingNode
}) {
  const planOrdering = pricing.planOrdering({
    itemFallback: 'free',
  })

  return (
    <div className="plans-table">
      {planOrdering.map((plan) => {
        const planContent = pricing.planContent({
          args: { plan },
        })
        return (
          <PlanColumn key={plan} planContent={planContent} />
        )
      })}
    </div>
  )
}

function PlanColumn({
  planContent,
}: {
  planContent: PlanContentNode
}) {
  const content = planContent.get()

  return (
    <div className="plan-column">
      <h3>{content.name}</h3>
      <p>{content.description}</p>
      <ul>
        {content.features.map((feature) => (
          <li key={feature}>{feature}</li>
        ))}
      </ul>
    </div>
  )
}
```

{% endcode %}

{% code title="components/FeaturesTable.tsx" %}

```tsx
import { type PricingNode } from '@/generated/hypertune'

export default function FeaturesTable({
  pricing,
}: {
  pricing: PricingNode
}) {
  const planOrdering = pricing.planOrdering({
    itemFallback: 'free',
  })
  const planFeatures = pricing.planFeatures()

  return (
    <table className="features-table">
      <thead>
        <tr>
          <th>Feature</th>
          {planOrdering.map((plan) => (
            <th key={plan}>{plan}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {planFeatures.map((feature) => {
          const featureName = feature.name({
            args: {},
            fallback: '',
          })
          return (
            <tr key={featureName}>
              <td>{featureName}</td>
              {planOrdering.map((plan) => {
                const value = feature
                  .value({ args: { plan } })
                  .get()
                return (
                  <td key={plan}>
                    {value.text ? (
                      <span className="text">{value.text}</span>
                    ) : value.isIncluded ? (
                      <span className="tick">✓</span>
                    ) : (
                      <span className="cross">✗</span>
                    )}
                  </td>
                )
              })}
            </tr>
          )
        })}
      </tbody>
    </table>
  )
}
```

{% endcode %}

This empowers product and marketing to instantly update and experiment on pricing from the Hypertune dashboard without any code changes or redeploys:

<div><figure><img src="https://2048905609-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWa3rQLiu4JZhBRkiyoKz%2Fuploads%2FxcRbJMygQxw9Tvq1wddR%2FScreenshot%202025-11-13%20at%2015.08.00.png?alt=media&#x26;token=a02f63de-6675-4353-aedf-dec789b6a592" alt=""><figcaption></figcaption></figure> <figure><img src="https://2048905609-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWa3rQLiu4JZhBRkiyoKz%2Fuploads%2FUhtEURIvR39rHIIWLW4D%2FScreenshot%202025-11-13%20at%2015.08.19.png?alt=media&#x26;token=a56f72cf-c79a-4d91-ba9f-36c688a2c74b" alt=""><figcaption></figcaption></figure></div>

## Benefits

* **Instant updates** — Adjust pricing across your frontend, backend, and marketing site without redeploying or coordinating code changes.
* **Empowered teams** — Product and marketing can update pricing independently, without waiting on engineering.
* **Faster iteration** — Tune pricing in real time to maximize revenue and growth.

## ROI

These benefits help teams:

* Ship more pricing improvements, faster, with the same headcount.
* Improve key business metrics, e.g. revenue.
