Overview
The definePlan() function defines a subscription plan with optional compile-time feature key restriction. When used with a generic type parameter, it ensures that only features defined in your configuration can be referenced.
Function Signature
function definePlan <
F extends Record < string , FeatureDefInput > = Record < string , FeatureDefInput >
>(
config : Omit < PlanDefInput , "features" | "prices" > & {
features : F extends Record < string , FeatureDefInput >
? Partial < Record < keyof F , PlanFeatureValue >>
: Record < string , PlanFeatureValue >;
prices ?: Array <
Omit < PriceDef , "overage_configuration" > & {
overage_configuration ?: F extends Record < string , FeatureDefInput >
? Partial < Record < keyof F , { overage_amount : number ; overage_unit : number }>>
: Record < string , { overage_amount : number ; overage_unit : number }>;
}
>;
}
) : PlanDefInput
Type Parameters
F
Record<string, FeatureDefInput>
default: "Record<string, FeatureDefInput>"
Feature dictionary type. Pass typeof yourFeatures for strict key validation. Omit for loose mode (backward compatible).
Parameters
The plan configuration object. Human-readable display name for the plan.
Optional description for marketing and documentation.
Whether this is the default plan. Exactly one plan must be default.
Whether this plan is visible on the public pricing page.
type
'paid' | 'free' | 'custom'
required
Commercial classification:
free: No payment required
paid: Requires active payment method
custom: Enterprise/B2B contracts with custom pricing
status
'draft' | 'active' | 'archived'
default: "active"
Lifecycle status:
draft: Not yet visible or purchasable
active: Live and available for subscription
archived: No longer available for new subscriptions
features
Record<string, PlanFeatureValue>
required
Feature entitlements included in this plan. Show PlanFeatureValue properties
Numeric limit (e.g., 5 seats, 10000 API calls).
Boolean toggle (e.g., SSO enabled/disabled).
Text value for display or metadata.
If true, usage is blocked when limit is reached. If false, overage is allowed.
reset_period
'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'
How often usage resets for metered features.
Optional pricing tiers. Free/default plans typically have no prices. Price amount in smallest currency unit (e.g., cents).
ISO 4217 currency code (e.g., “USD”, “EUR”).
billing_interval
'monthly' | 'quarterly' | 'yearly' | 'one_time'
required
How often the customer is billed.
Number of days for a free trial before billing starts.
Whether this price is currently active.
overage_configuration
Record<string, { overage_amount: number; overage_unit: number }>
Overage pricing for metered features. Maps feature slugs to their overage terms.
Slugs of addons that can be attached to this specific price/interval.
Returns
The plan configuration, normalized to PlanDefInput type.
Usage
Strict Mode (Type-Safe Feature Keys)
import { defineConfig , defineFeature , definePlan } from "@revstack/core" ;
const features = {
seats: defineFeature ({
name: "Team Seats" ,
type: "static" ,
unit_type: "count" ,
}),
storage: defineFeature ({
name: "Storage" ,
type: "metered" ,
unit_type: "bytes" ,
}),
};
export default defineConfig ({
features ,
plans: {
pro: definePlan < typeof features >({
name: "Pro" ,
is_default: false ,
is_public: true ,
type: "paid" ,
features: {
seats: { value_limit: 10 },
storage: { value_limit: 100_000_000_000 },
// typo_feature: { value_bool: true }, // ❌ Compile error!
},
}),
} ,
}) ;
Loose Mode (Backward Compatible)
import { definePlan } from "@revstack/core" ;
export const starter = definePlan ({
name: "Starter" ,
is_default: true ,
is_public: true ,
type: "free" ,
features: {
seats: { value_limit: 3 },
anything: { value_bool: true }, // ✅ Any key accepted
},
});
Free Plan
import { definePlan } from "@revstack/core" ;
export const free = definePlan ({
name: "Free" ,
description: "Perfect for individuals and small projects" ,
is_default: true ,
is_public: true ,
type: "free" ,
features: {
seats: { value_limit: 1 },
projects: { value_limit: 3 },
storage: { value_limit: 1_000_000_000 }, // 1 GB
api_calls: {
value_limit: 1000 ,
reset_period: "monthly" ,
is_hard_limit: true ,
},
},
// No prices array for free plans
});
Paid Plan with Multiple Intervals
import { definePlan } from "@revstack/core" ;
export const pro = definePlan ({
name: "Pro" ,
description: "For growing teams" ,
is_default: false ,
is_public: true ,
type: "paid" ,
features: {
seats: { value_limit: 10 },
projects: { value_limit: 50 },
storage: { value_limit: 100_000_000_000 }, // 100 GB
api_calls: {
value_limit: 50000 ,
reset_period: "monthly" ,
is_hard_limit: false , // Allow overage
},
},
prices: [
{
amount: 2900 ,
currency: "USD" ,
billing_interval: "monthly" ,
trial_period_days: 14 ,
available_addons: [ "extra_seats" ],
},
{
amount: 29000 ,
currency: "USD" ,
billing_interval: "yearly" ,
trial_period_days: 14 ,
available_addons: [ "extra_seats" ],
},
],
});
Plan with Overage Pricing
import { definePlan } from "@revstack/core" ;
export const business = definePlan ({
name: "Business" ,
is_default: false ,
is_public: true ,
type: "paid" ,
features: {
api_calls: {
value_limit: 100000 ,
reset_period: "monthly" ,
is_hard_limit: false , // Allow overage
},
},
prices: [
{
amount: 9900 ,
currency: "USD" ,
billing_interval: "monthly" ,
overage_configuration: {
api_calls: {
overage_amount: 10 , // $0.10 per unit
overage_unit: 1000 , // Per 1000 API calls
},
},
},
],
});
Enterprise/Custom Plan
import { definePlan } from "@revstack/core" ;
export const enterprise = definePlan ({
name: "Enterprise" ,
description: "Custom pricing and unlimited resources" ,
is_default: false ,
is_public: true ,
type: "custom" , // No prices array, redirects to "Contact Sales"
features: {
seats: { value_bool: true }, // Unlimited
projects: { value_bool: true },
storage: { value_bool: true },
sso: { value_bool: true },
},
});
Source
Location : packages/core/src/define.ts:41-60