Plans and pricing
Define what you sell in src/config.ts. Subscriptions, one-time purchases, prices and currencies, and how to change them safely.
Everything you sell is a plan in src/config.ts. The pricing section on the landing page, the checkout buttons and the dashboard all read from this list. Each plan becomes one product in Dodo.
export const plans: Plan[] = [
{
slug: 'starter',
name: 'Starter',
description: 'For freelancers getting started.',
amount: 1200, // $12.00
currency: 'USD',
interval: 'month', // "month", "year", or null for one-time
features: ['Unlimited invoices', 'Automatic reminders'],
productEnv: 'DODO_PRODUCT_STARTER',
},
{
slug: 'lifetime',
name: 'Lifetime',
description: 'Pay once, use it forever.',
amount: 9900, // $99.00
currency: 'USD',
interval: null, // one-time payment
features: ['Everything, forever'],
productEnv: 'DODO_PRODUCT_LIFETIME',
featured: true, // highlighted on the pricing section
},
];Fields
| Field | What it does |
|---|---|
slug | Permanent ID for the plan. Used in URLs (/sign-up?plan=pro) and to find the plan's Dodo product. Don't change it once you've sold the plan |
name, description, features | Shown on the pricing cards. name and description also become the Dodo product's |
amount | Price in the currency's smallest unit: 1900 = $19.00, 49900 = ₹499.00 |
currency | Three-letter code, such as USD, INR or EUR |
interval | "month" or "year" for a subscription; null for a one-time payment |
productEnv | Name of the environment variable that holds this plan's Dodo product ID. Must be unique, such as DODO_PRODUCT_<SLUG> |
featured | Optional. Highlights the card |
Add a plan
Add it to plans in src/config.ts with a new slug and productEnv.
Add the variable to .env.example, for example DODO_PRODUCT_LIFETIME=, so others setting up the project know about it.
Run npm run setup. Keep the steps you've finished; the payments step creates the new product and saves its ID to .env.local.
If you've deployed, re-run setup with deploy, or add the new DODO_PRODUCT_… variable in Vercel and redeploy.
Remove a plan
Delete it from plans and its line from .env.example. Existing customers keep their access: the dashboard shows a purchase of a plan that's no longer in the config as paid. Archive the product in Dodo so nobody can buy it from an old link.
Changing a plan's price
Setup finds each plan's product by a tag holding its slug, and reuses it without changing the price. So editing amount alone changes the price on your website but not at checkout. Pick one:
- Change
amountinsrc/config.ts. - In Dodo, open Products, find the plan's product (its ID is in
.env.localas the plan'sproductEnv), and change its price to match.
Existing subscribers stay on the price they signed up at, unless you change their subscription in Dodo.
Keep both in sync
The website shows amount from src/config.ts; checkout charges the Dodo product's price. If they differ, customers see one price and pay another.
Prices in other currencies
Set currency to any currency Dodo supports. Dodo can also show local prices to buyers in other countries (purchasing power parity), which you turn on per product in the Dodo dashboard.
Format money anywhere in the app with formatMoney() from src/lib/format.ts. Money is always stored as integers in the smallest unit.
Subscription length
Subscriptions created by setup renew every month or year until the customer cancels.