Documentation
supastarter for Next.jsPayments

Manage plans and products

Learn how to manage plans and products in your application.

Pricing table

Define plans and products

You can manage the plans and products in the configuration file of your supastarter project.

There are different types of plans you can define:

Free plan

The free plan is the default plan for users who have not purchased any plans or can be used to access a limited version of your product.

As this is no paid plan, you don't need to define any prices or attach a product id to it.

export const config = {
  payments: {
    plans: {
        free: {
            isFree: true,
        },
    }
  },
};

Enterprise plan

The enterprise plan is not a real plan, but will show up in the pricing table with a link to a contact form, so customers can contact you to get access to your product.

As this is no paid plan, you don't need to define any prices or attach a product id to it.

export const config = {
  payments: {
    plans: {
        enterprise: {
            isEnterprise: true,
        },
    }
  },
};

Subscription plans and one-time purchase plans

A plan represents a product or service of your application and each is a column in your pricing table. It has the following properties:

  • recommended: if this plan should be highlighted as recommended
  • hidden: hide the plan from the pricing table, can be used if you want to grandfather old plans or prepare for a new plan
  • prices: define the prices for this plan

One plan can have multiple prices, for example a monthly and yearly price or/and for each currency you support.

A price has the following properties:

  • type: the type of the price, can be recurring or one_time
  • productId: the id of the product from the payment provider
  • interval: the interval of the price, can be month, year, week or day
  • intervalCount: the number of intervals to bill, defaults to 1
  • amount: the amount of the price
  • currency: the currency of the price, for example USD
  • trialPeriodDays: the number of days of the trial period, leave out if you don't want to offer a trial period
  • seatBased: if price is per seat (this will only work for organizations and will multiply the price by the number of members), defaults to false

You can publish your site with a placeholder productId, if you need a landing page with pricing table to verify your store in Stripe or Lemonsqueezy. Just note that this will not work in production.

export const config = {
  payments: {
    plans: {
        pro: {
            recommended: true,
            prices: [
                {
                    type: "recurring",
                    productId: "price_as34asdflkh134kh",
                    interval: "month",
                    amount: 29,
                    currency: "USD",
                    trialPeriodDays: 7,
                    seatBased: true,
                },
                {
                    type: "recurring",
                    productId: "price_as34asdflkh134kh",
                    interval: "year",
                    amount: 290,
                    currency: "USD",
                    trialPeriodDays: 7,
                    seatBased: true,
                },
            ],
        },
        lifetime: {
            prices: [
                {
                    type: "one_time",
                    productId: "price_as34asdflkh134kh",
                    amount: 999,
                    currency: "USD",
                },
            ],
        },
    }
  },
};

Support multiple currencies

To support multiple currencies, make sure to define the different currencies for each locale in the i18n section of the config file:

export const config = {
  i18n: {
    locales: {
        en: {
            currency: "USD",
        },
        de: {
            currency: "EUR",
        },
    }
  },
};

Then define the prices for each locale in the payments.plans section of the config file:

export const config = {
  payments: {
    plans: {
        pro: {
            prices: [
                {
                    type: "recurring",
                    productId: "price_as34asdflkh134kh",
                    interval: "month",
                    amount: 29,
                    currency: "USD"
                },
                {
                    type: "recurring",
                    productId: "price_as34asdflkh134kh",
                    interval: "month",
                    amount: 29,
                    currency: "EUR"
                },
            ],
        },
    }
  },
};

Plan information for pricing table

You can define the information for the pricing table for each plan in the usePlanData hook in /apps/web/modules/saas/payments/hooks/plan-data.ts.

You can define a title, a description and a features array for each plan.

We recommend you to use the t() function to get the translations for the plan information and then define the translations in the /packages/i18n/translations/ folder.

export function usePlanData() {
	const t = useTranslations();
 
	const planData: Record<
		ProductReferenceId,
		{
			title: string;
			description: ReactNode;
			features: ReactNode[];
		}
	> = {
		free: {
			title: t("pricing.products.free.title"),
			description: t("pricing.products.free.description"),
			features: [
				t("pricing.products.free.features.anotherFeature"),
				t("pricing.products.free.features.limitedSupport"),
			],
		},
		pro: {
			title: t("pricing.products.pro.title"),
			description: t("pricing.products.pro.description"),
			features: [
				t("pricing.products.pro.features.anotherFeature"),
				t("pricing.products.pro.features.fullSupport"),
			],
		},
		enterprise: {
			title: t("pricing.products.enterprise.title"),
			description: t("pricing.products.enterprise.description"),
			features: [
				t("pricing.products.enterprise.features.unlimitedProjects"),
				t("pricing.products.enterprise.features.enterpriseSupport"),
			],
		},
	};
 
	return { planData };
}

On this page