Plans & Products
Learn how to manage plans and products in your application.
Plans and products are defined in config/billing.config.ts. This configuration determines what plans are available, their pricing, and how they appear in your pricing table.
Storage limits are metadata
The shipped kit does not meter stored objects or enforce
maxStorage. Storage amounts in feature lists and plan limits are
display and configuration metadata until you add usage tracking and
server-side guards.
Plan Types
The starter kit supports several plan types:
Free Plan
The free plan is the default plan for users who haven't purchased any paid plans. It provides limited access to your product.
export const billingConfig = {
plans: {
free: {
id: 'free',
name: 'Free',
description: 'Get started with basic features',
isFree: true,
features: [
'Up to 3 team members',
'Basic analytics',
'Community support'
],
limits: {
maxMembers: 3,
maxStorage: 1 // GB
}
// No prices needed for free plans
}
}
};Subscription Plans
Subscription plans charge users on a recurring basis (monthly, yearly, etc.):
import { env } from '@/lib/env';
export const billingConfig = {
plans: {
pro: {
id: 'pro',
name: 'Pro',
description: 'For growing teams',
recommended: true, // Highlights this plan in the pricing table
features: [
'Unlimited team members',
'Advanced analytics',
'Priority support',
'100 GB storage'
],
limits: {
maxMembers: -1, // unlimited
maxStorage: 100 // GB
},
prices: [
{
id: 'pro_monthly',
stripePriceId: env.NEXT_PUBLIC_STRIPE_PRICE_PRO_MONTHLY ?? '',
type: 'recurring',
interval: 'month',
intervalCount: 1,
amount: 2900, // $29.00 in cents
currency: 'usd',
seatBased: true, // Per-seat pricing
trialDays: 14 // Optional: 14-day free trial
},
{
id: 'pro_yearly',
stripePriceId: env.NEXT_PUBLIC_STRIPE_PRICE_PRO_YEARLY ?? '',
type: 'recurring',
interval: 'year',
intervalCount: 1,
amount: 27800, // $278.00 in cents
currency: 'usd',
seatBased: true,
trialDays: 14
}
]
}
}
};One-Time Purchase Plans
One-time purchase plans charge users a single upfront payment:
import { env } from '@/lib/env';
export const billingConfig = {
plans: {
lifetime: {
id: 'lifetime',
name: 'Lifetime',
description: 'Pay once, use forever',
features: [
'All Pro features',
'Lifetime updates',
'Priority support for 1 year'
],
limits: {
maxMembers: -1,
maxStorage: 100
},
prices: [
{
id: 'lifetime_once',
stripePriceId: env.NEXT_PUBLIC_STRIPE_PRICE_LIFETIME ?? '',
type: 'one_time',
amount: 49900, // $499.00 in cents
currency: 'usd'
}
]
}
}
};Enterprise Plan
Enterprise plans show up in the pricing table with a link to a contact form:
export const billingConfig = {
plans: {
enterprise: {
id: 'enterprise',
name: 'Enterprise',
description: 'For large organizations with custom needs',
isEnterprise: true,
features: [
'Everything in Pro',
'Dedicated account manager',
'Custom SLA',
'Unlimited storage',
'SSO / SAML'
],
limits: {
maxMembers: -1,
maxStorage: -1
}
// No prices needed - users contact you directly
}
}
};Price Properties
Each price object supports the following properties:
id: Unique identifier for the price (e.g.,"pro_monthly")type:"recurring"or"one_time"stripePriceId: The Stripe Price ID (from environment variables, starts withprice_)interval: For recurring plans:"month","year","week"or"day"intervalCount: Number of intervals to bill (defaults to 1)amount: The price amount (in cents for Stripe)currency: Currency code (e.g.,"usd","eur")trialDays: Optional trial period in daysseatBased: Iftrue, price is per seat (multiplies by number of organization members)
Plan Configuration Options
recommended: Highlights the plan in the pricing tablehidden: Hides the plan from the pricing table (useful for grandfathering old plans)
Creating Plans in Stripe
- Go to your Stripe Dashboard
- Navigate to Products > Add product
- Create your product with pricing
- Copy the Price ID (starts with
price_) - Add it to your environment variables:
NEXT_PUBLIC_STRIPE_PRICE_PRO_MONTHLY=price_xxxxx
NEXT_PUBLIC_STRIPE_PRICE_PRO_YEARLY=price_xxxxx
NEXT_PUBLIC_STRIPE_PRICE_LIFETIME=price_xxxxxPlan Limits
You can define plan limits in config/billing.config.ts:
export const billingConfig = {
plans: {
pro: {
// ... prices
limits: {
maxMembers: 10, // Maximum organization members
maxStorage: 50 // GB of plan metadata
}
}
}
};The shipped invitation guards enforce maxMembers. maxStorage is plan
metadata until you add stored-byte usage tracking and a server-side guard. To
add another limit such as maxProjects, extend the billing schema and enforce
it on every relevant server mutation.