Configuration
The Fast Forward Dev client uses a centralized configuration system located in /src/config/config.ts. This file controls environment detection, product types, backend connectivity, theming, and Stripe integration.
Main Configuration File
Location
src/config/config.tsOverview
The configuration file exports:
isProd()- Environment detection functionProductType- Enum for Stripe product typesappConfig- Main configuration object
Environment Detection
isProd() Function
export const isProd = () => process.env.NODE_ENV === 'production'This utility function determines if the application is running in production mode. It’s used throughout the app to switch between development and production settings.
Usage:
import { isProd } from '@/config/config'
if (isProd()) {
// Use production settings
} else {
// Use development settings
}Product Types
ProductType Enum
export enum ProductType {
BASIC = 'basic',
PRO = 'pro',
}This enum defines the available product tiers for your application. You can add more tiers as needed.
Adding a New Product Type:
export enum ProductType {
BASIC = 'basic',
PRO = 'pro',
ENTERPRISE = 'enterprise', // New tier
}When adding new product types, you must also add corresponding Stripe price IDs in the configuration below.
Main Configuration Object
appConfig Structure
export const appConfig = {
nextConfig: {
backendUrl: string,
theme: string,
},
siteName: string,
stripe: {
publicKey: string,
priceIds: Record<ProductType, string>,
},
}Next.js Configuration
Backend URL
nextConfig: {
backendUrl: isProd()
? 'https://fast-forward-dev-6564a4547efb.herokuapp.com'
: 'http://localhost:5001',
}Controls which backend server the client connects to.
Development:
- Points to
http://localhost:5001 - Your local Express server
Production:
- Points to your deployed backend
- Update this URL after deploying your server
Customization:
backendUrl: isProd()
? 'https://your-production-backend.com' // Your production URL
: 'http://localhost:5001',If you change the local port, update both the backend .env file and this configuration.
Theme
nextConfig: {
theme: 'ffd',
}Specifies which DaisyUI theme to use. The ‘ffd’ theme is a custom theme defined in src/app/globals.css using Tailwind CSS v4 syntax.
Available Options:
'ffd'- Custom Fast Forward Dev theme (default)- Any DaisyUI theme (e.g., ‘light’, ‘dark’, ‘cupcake’, ‘corporate’)
The FFD Theme:
The custom FFD theme is defined in src/app/globals.css:
@plugin "daisyui/theme" {
name: "ffd";
default: true;
prefersdark: false;
color-scheme: "light";
/* Primary - Bright blue #007dff */
--color-primary: oklch(60% 0.22 250);
--color-primary-content: oklch(99% 0 0);
/* Secondary - Muted green #5d8562 */
--color-secondary: oklch(55% 0.06 150);
--color-secondary-content: oklch(100% 0 0);
/* ... more colors */
}Customization:
To change the theme to a DaisyUI preset:
theme: 'dark', // Use DaisyUI's dark themeTo customize the FFD theme colors, edit src/app/globals.css:
@plugin "daisyui/theme" {
name: "ffd";
--color-primary: oklch(65% 0.25 270); /* New purple color */
--color-secondary: oklch(60% 0.18 180); /* New teal color */
/* ... customize other colors */
}Fast Forward Dev uses Tailwind CSS v4 syntax with DaisyUI. Learn more at DaisyUI Themes .
Site Name
siteName: 'Fast Forward Dev',The name of your application. Used in:
- Page titles
- Meta tags
- Email templates
- Footer
Customization:
siteName: 'My Awesome App',After changing the site name, update it in other places like layout.tsx metadata and email templates.
Stripe Configuration
Public Key
stripe: {
publicKey: isProd()
? process.env.PUBLIC_STRIPE_PUBLISHABLE_KEY
: process.env.PUBLIC_TEST_STRIPE_PUBLISHABLE_KEY,
}Automatically selects the correct Stripe publishable key based on environment.
Development:
- Uses
PUBLIC_TEST_STRIPE_PUBLISHABLE_KEYfrom.env.local - Test mode key (starts with
pk_test_)
Production:
- Uses
PUBLIC_STRIPE_PUBLISHABLE_KEYfrom.env.local - Live mode key (starts with
pk_live_)
Price IDs
const productType = isProd()
? {
[ProductType.BASIC]: 'price_1P3s4xP4McnT55wKrtb3OPsc',
[ProductType.PRO]: 'price_1PED7uP4McnT55wKre6G3Rjd',
}
: {
[ProductType.BASIC]: 'price_1SahUM1DJWXEccvOnwl9U0g7',
[ProductType.PRO]: 'price_1SahiD1DJWXEccvOkfp8zjKQ',
}
stripe: {
priceIds: productType,
}Maps product types to Stripe price IDs. Separate IDs for test and production modes.
Getting Price IDs:
- Go to Stripe Dashboard
- Navigate to “Products”
- Create or select a product
- Create a price (one-time or recurring)
- Copy the price ID (starts with
price_)
Customization:
const productType = isProd()
? {
[ProductType.BASIC]: 'price_live_basic_id',
[ProductType.PRO]: 'price_live_pro_id',
[ProductType.ENTERPRISE]: 'price_live_enterprise_id', // New tier
}
: {
[ProductType.BASIC]: 'price_test_basic_id',
[ProductType.PRO]: 'price_test_pro_id',
[ProductType.ENTERPRISE]: 'price_test_enterprise_id', // New tier
}Always create separate test and production prices in Stripe. Never use production price IDs in development.
Using Configuration in Your App
Importing
import { appConfig, isProd, ProductType } from '@/config/config'Accessing Values
// Get backend URL
const backendUrl = appConfig.nextConfig.backendUrl
// Get site name
const siteName = appConfig.siteName
// Get Stripe public key
const stripeKey = appConfig.stripe.publicKey
// Get price ID for a specific product
const basicPriceId = appConfig.stripe.priceIds[ProductType.BASIC]Example: Making API Calls
import { appConfig } from '@/config/config'
async function fetchUser() {
const response = await fetch(`${appConfig.nextConfig.backendUrl}/api/user`, {
headers: {
'Authorization': `Bearer ${token}`,
},
})
return response.json()
}Example: Stripe Checkout
import { appConfig, ProductType } from '@/config/config'
import { loadStripe } from '@stripe/stripe-js'
const stripe = await loadStripe(appConfig.stripe.publicKey!)
const { error } = await stripe.redirectToCheckout({
lineItems: [{
price: appConfig.stripe.priceIds[ProductType.PRO],
quantity: 1,
}],
mode: 'payment',
successUrl: `${window.location.origin}/thank-you`,
cancelUrl: `${window.location.origin}/pricing`,
})Stripe Configuration File
Location
src/config/stripe.tsPurpose
Initializes the Stripe SDK for server-side operations (API routes).
import Stripe from 'stripe'
const stripeKey =
process.env.NODE_ENV === 'production'
? process.env.STRIPE_SECRET_KEY
: process.env.STRIPE_TEST_SECRET_KEY
const stripe = new Stripe(stripeKey, {
apiVersion: '2025-11-17.clover',
})
export default stripeThis file uses secret keys (not publishable keys). It should only be imported in API routes, never in client components.
Usage in API Routes
import stripe from '@/config/stripe'
export async function POST(req: Request) {
const session = await stripe.checkout.sessions.create({
// ... session config
})
return Response.json({ sessionId: session.id })
}Complete Configuration Example
Here’s a fully customized configuration:
export const isProd = () => process.env.NODE_ENV === 'production'
export enum ProductType {
STARTER = 'starter',
PROFESSIONAL = 'professional',
ENTERPRISE = 'enterprise',
}
const productType = isProd()
? {
[ProductType.STARTER]: 'price_live_starter',
[ProductType.PROFESSIONAL]: 'price_live_professional',
[ProductType.ENTERPRISE]: 'price_live_enterprise',
}
: {
[ProductType.STARTER]: 'price_test_starter',
[ProductType.PROFESSIONAL]: 'price_test_professional',
[ProductType.ENTERPRISE]: 'price_test_enterprise',
}
export const appConfig = {
nextConfig: {
backendUrl: isProd()
? 'https://api.myapp.com'
: 'http://localhost:5001',
theme: 'corporate',
},
siteName: 'My SaaS App',
stripe: {
publicKey: isProd()
? process.env.PUBLIC_STRIPE_PUBLISHABLE_KEY
: process.env.PUBLIC_TEST_STRIPE_PUBLISHABLE_KEY,
priceIds: productType,
},
}Best Practices
Environment Variables
- Store sensitive keys in
.env.local(never commit to Git) - Use different keys for development and production
- Prefix client-side variables with
PUBLIC_
Configuration Updates
- Update
backendUrlafter deploying your server - Keep price IDs in sync with Stripe Dashboard
- Test configuration changes in development first
Type Safety
The configuration is fully typed, so TypeScript will catch errors:
// ✅ Correct
const priceId = appConfig.stripe.priceIds[ProductType.BASIC]
// ❌ TypeScript error - typo in ProductType
const priceId = appConfig.stripe.priceIds[ProductType.BASIK]Troubleshooting
”Cannot connect to backend” errors
- Verify
backendUrlis correct - Check that backend server is running
- Ensure CORS is configured on backend
Stripe errors
- Verify you’re using the correct keys (test vs. live)
- Check price IDs match your Stripe Dashboard
- Ensure public key is accessible (starts with
pk_)
Theme not applying
- Check theme name matches
tailwind.config.ts - Verify DaisyUI is installed
- Clear Next.js cache:
rm -rf .next
Next Steps
- Components Overview - Learn about UI components
- Stripe Payments - Set up payments
- DaisyUI Themes - Customize your design with DaisyUI themes