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:
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:
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 = 'nodejs'
export async function GET(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,
})
}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>
)
}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>
)
}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>
)
}This empowers product and marketing to instantly update and experiment on pricing from the Hypertune dashboard without any code changes or redeploys:


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.
Last updated