Codapult
PricingPluginsBlogDocsDemo
Logo

The SaaS Boilerplate for Builders

© 2026 Codapult. All rights reserved.

Built with Codapult

Product

  • Pricing
  • Plugins
  • Blog
  • Documentation

Alternatives

  • SaaS template comparison
  • Codapult vs Supastarter
  • Codapult vs Makerkit
  • Codapult vs ShipFast
  • Codapult vs SaaSBold
  • Codapult vs Gravity
  • Codapult vs Nextbase
  • Codapult vs BuilderKit

About

  • Contact

Legal

  • Privacy Policy
  • Terms of Service
All articles

Getting Started

  • Introduction
  • Quick Start
  • Project Structure
  • License and Permitted Use

Configuration

  • Environment Variables
  • App Configuration

Authentication

  • Authentication
  • OAuth Providers
  • Two-Factor & Passwordless
  • Enterprise SSO (SAML)

Database

  • Database
  • Migrations

Teams

  • Teams & Organizations
  • Permissions & RBAC
  • SCIM Provisioning

Payments

  • Payments & Billing
  • Stripe Setup
  • LemonSqueezy Setup
  • Polar Setup
  • Payment Webhooks

Api

  • API Layer
  • tRPC
  • GraphQL

Ai

  • AI Features
  • Streaming Chat
  • RAG and Semantic Search
  • Quotas and Memory

Email

  • Email
  • Email Templates

Infrastructure

  • Infrastructure
  • Self-Hosting
  • File Storage
  • Docker
  • Background Jobs
  • Terraform & Pulumi
  • Kubernetes

Ui

  • UI & Theming

I18n

  • Internationalization

Content Management

  • Content Management

Admin

  • Admin Panel

Security

  • Security

Monitoring

  • Analytics & Monitoring

Modules

  • Module Architecture
  • Waitlist
  • Audit Log
  • White-Labeling
  • Workflow Automation
  • A/B Testing
  • Welcome Page
  • Referrals
  • GDPR Export and Deletion
  • Outgoing Webhooks

Plugins

  • Plugin System
  • AI Kit Plugin
  • CRM Plugin
  • Helpdesk Plugin
  • Email Marketing Plugin

Deployment

  • Deployment
  • Troubleshooting

Upgrading

  • Upgrading Codapult

Developer Tools

  • AI Agents & IDEs
  • MCP Server
  • Testing
Configuration

App Configuration

Customize your brand, features, navigation, pricing, and AI settings through Codapult's configuration files.

Codapult's behavior is controlled through a small set of TypeScript configuration files. These are the files you'll edit most when making the product your own.

FilePurpose
src/config/app.tsBrand identity, static AI limits/prompts, and company settings
src/config/navigation.tsDashboard and admin sidebar items
src/config/marketing.tsClient-safe landing page data: stats, testimonials, module cards
src/config/marketing-pricing.tsServer-side pricing, checkout links, plugin catalog
src/config/competitor-comparison.tsCompare and vs page data
src/lib/config.tsTyped env var access, feature toggles (env.features), auth, payments (hand-maintained Zod schema)

App identity

Edit src/config/app.ts to set your product identity:

const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? 'http://localhost:3000';

export const appConfig = {
  appUrl,
  serverUrl: process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : appUrl,
  appName: process.env.NEXT_PUBLIC_APP_NAME ?? 'my-app',
  brand: {
    name: 'My App',
    description: 'The best project management tool for teams',
    logo: '/logo.svg',
    showBuiltWithBadge: true,
    icons: {
      favicon: '/favicon.ico',
      svg: '/icon.svg',
      apple: '/apple-icon.png',
      pwa192: '/icon-192.png',
      pwa512: '/icon-512.png',
    },
  },
  // ...
};
PropertySourceDescription
appUrlNEXT_PUBLIC_APP_URL env varCanonical public URL (auth callbacks, emails, SEO). Defaults to http://localhost:3000 for dev.
serverUrlVERCEL_URL → appUrlSSR self-reference URL for server-side fetches (tRPC). On Vercel, uses the deployment URL; otherwise falls back to appUrl.
appNameNEXT_PUBLIC_APP_NAME env varTechnical project name (lowercase). Used for OTEL service name and machine identifiers.
brand.nameHardcoded in sourceDisplay name (proper case). Shown in sidebar, emails, meta tags, PWA manifest. Edit directly in app.ts.
brand.descriptionHardcoded in sourceShort product description for SEO meta tags.
brand.logoHardcoded in sourcePath to logo image (relative to /public).
brand.showBuiltWithBadgeHardcoded in sourceShows or hides the small "Built with" badge in the marketing footer.
brand.iconsHardcoded in sourceBrand icon paths: favicon (.ico), svg, apple (180×180), pwa192, pwa512. Wired into <head> metadata and PWA manifest. Drop your files at these paths in public/ (favicon.ico lives in src/app/) or change the paths here.

The brand.name display name propagates to manifest.ts, layout.tsx metadata, and email templates automatically. The appUrl is used everywhere: robots.ts, sitemap.ts, auth callbacks, Stripe redirects, invite links, and email links. The serverUrl is used by tRPC for SSR data fetching — on Vercel preview deployments it points to the correct deployment URL instead of the production domain.


Feature toggles

All feature toggles live in environment variables (prefix ENABLE_*). They are surfaced server-side via env.features in src/lib/config.ts, and both the navigation and src/proxy.ts use the same source to hide UI and block routes.

All toggles default to true. Set the corresponding env var to false to disable the feature — its routes return 404 and its sidebar/footer entries disappear.

Env varFeatureDefault
ENABLE_AI_CHATAI chat assistant (Vercel AI SDK, streaming)true
ENABLE_TEAMSOrganizations, multi-tenancy, team invitationstrue
ENABLE_BLOGMDX blog with i18n, tags, and authorstrue
ENABLE_HELP_CENTERHelp center / documentation (MDX)true
ENABLE_WAITLISTWaitlist with email confirmationtrue
ENABLE_REFERRALSReferral / affiliate programtrue
ENABLE_ANALYTICSSelf-serve analytics dashboardtrue
ENABLE_WORKFLOWSEvent-triggered workflow automationtrue
ENABLE_WEBHOOKSOutgoing webhooks (HMAC signed)true
ENABLE_AUDIT_LOGUser-facing activity / audit logtrue
ENABLE_REPORTSScheduled email reportstrue
ENABLE_FEATURE_REQUESTSPublic feature request voting boardtrue
ENABLE_CHANGELOGIn-app "What's new" changelog widgettrue
ENABLE_ONBOARDINGInteractive onboarding tourstrue
ENABLE_BRANDINGPer-org white-labelingtrue
ENABLE_SSOEnterprise SSO (SAML via BoxyHQ)true
ENABLE_EXPERIMENTSA/B testing frameworktrue
ENABLE_DRIP_CAMPAIGNSEmail drip campaignstrue
ENABLE_TWO_FACTORTOTP-based two-factor authenticationtrue
ENABLE_PLUGINSPremium plugin marketplace (/plugins, /dashboard/plugins)true
ENABLE_API_DOCSInteractive OpenAPI reference page (/docs/api)true

Each ENABLE_* flag is independent — disabling auth (AUTH_PROVIDER=none) does not cascade to other features. The only exception is twoFactor, which is meaningless without an auth provider and is therefore force-disabled when AUTH_PROVIDER=none. Dashboard-only modules (aiChat, teams, referrals, etc.) keep their flags but their pages live under /dashboard/*, which is itself 404 when auth is off; their public-facing parts (e.g. /feature-requests, /changelog) remain accessible until you flip the matching ENABLE_* flag (the CLI setup --preset marketing does this for you).


Auth configuration

Sign-in methods are controlled by environment variables:

VariableDefaultDescription
AUTH_MAGIC_LINK"true"Passwordless email sign-in via magic link. Set to "false" to disable.
AUTH_PASSKEYS"true"WebAuthn / passkey authentication. Set to "false" to disable.

Both are read via env.auth.magicLink and env.auth.passkeys in src/lib/config.ts.

OAuth providers appear automatically when both <PROVIDER>_CLIENT_ID and <PROVIDER>_CLIENT_SECRET env vars are set (supported: google, github, apple, discord, twitter, microsoft).

Two-factor authentication (TOTP) is controlled by ENABLE_TWO_FACTOR — see Feature toggles.


AI configuration

Customize the AI chat assistant behavior (src/config/app.ts):

ai: {
  defaultModel: 'gpt-4o-mini',
  systemPrompt: 'You are a helpful AI assistant. Be concise, accurate, and helpful.',
  ragEnabled: true,
  ragMaxChunks: 3,
  ragMinScore: 0.4,
  allowedModels: [],
},
PropertyTypeDescription
defaultModelstringDefault model ID. Must match an entry in src/lib/ai/models.ts
systemPromptstringSystem prompt prepended to every conversation
ragEnabledbooleanEnable retrieval-augmented generation in chat
ragMaxChunksnumberMaximum context chunks injected from RAG
ragMinScorenumberMinimum cosine similarity score for RAG results (0–1)
allowedModelsstring[]Models shown in the chat model selector. Empty array = all models from models.ts

Company links

Set company contact details used in the Privacy Policy, Terms of Service, and footer (src/config/app.ts):

company: {
  contactEmail: 'support@myapp.com',
  githubUrl: 'https://github.com/myorg/myapp',
},
PropertyTypeDescription
contactEmailstringContact email used in legal pages (Privacy Policy, Terms)
githubUrlstringGitHub URL shown in the footer. Hidden if empty

Navigation

Edit src/config/navigation.ts to customize sidebar items for the dashboard and admin panel.

Each item has a href, label, icon (from Lucide), and an optional featureKey:

import type { env } from '@/lib/config';

export interface NavItem {
  href: string;
  label: string;
  icon: LucideIcon;
  featureKey?: keyof typeof env.features;
}

When featureKey is set, the item is automatically hidden if that feature is disabled in env.features (see the Feature toggles table).

Dashboard sidebar

export const dashboardNavItems: NavItem[] = [
  { href: '/dashboard', label: 'Dashboard', icon: LayoutDashboard },
  { href: '/dashboard/ai-chat', label: 'AI Chat', icon: MessageSquare, featureKey: 'aiChat' },
  { href: '/dashboard/analytics', label: 'Analytics', icon: BarChart3, featureKey: 'analytics' },
  { href: '/dashboard/billing', label: 'Billing', icon: CreditCard },
  // ...add your own items here
];

Admin sidebar

export const adminNavItems: NavItem[] = [
  { href: '/admin', label: 'Overview', icon: ShieldCheck },
  { href: '/admin/users', label: 'Users', icon: Users },
  { href: '/admin/subscriptions', label: 'Subscriptions', icon: CreditCard },
  { href: '/admin/feature-flags', label: 'Feature Flags', icon: Flag },
  // ...
];

To add a custom page, create the route in src/app/[locale]/(dashboard)/dashboard/your-page/page.tsx and add a corresponding entry to dashboardNavItems.


Marketing configuration

The shipped marketing routes describe Codapult. Replace them with your own product's claims, pricing, screenshots, legal copy, and docs before deploying a customer-facing SaaS.

Edit these files together:

FileWhat it controls
src/app/[locale]/(marketing)/page.tsxLanding page section order
src/components/marketing/*Landing, pricing, plugins, navbar, footer, CTA sections
src/config/marketing.tsClient-safe landing data: stats, module cards, testimonials
src/config/marketing-pricing.tsPricing tiers, checkout links, premium plugin cards
src/config/competitor-comparison.ts/compare, /compare/[competitor] data
messages/*.jsonLocalized marketing copy and CTA labels
content/blog/, content/docs/Public MDX content and RSS/help-center pages

If you do not need a surface at launch, disable it with the matching ENABLE_* env var where available and remove it from navigation, sitemap, and footer links.

Pricing tiers

export const pricingTiers: Record<TierKey, PricingTier> = {
  starter: {
    key: 'starter',
    ...getPriceInfo(49, 99),
    link: checkoutHref(env.checkout.starter, env.checkout.variants.starter, 'starter', '/sign-up'),
    featureKeys: ['tierFeatureProject1', 'tierFeatureUpdates6', 'tierFeatureCommunity'],
  },
  // ... pro (featured), enterprise
};

Feature labels are stored in messages/en.json under the "ProductPricing" namespace, so they support i18n. The key maps to a translation key for the tier name.

Set featured: true on a tier to visually highlight it. The link property is created by checkoutHref() in src/config/marketing-pricing.ts: variant IDs route through /api/checkout?product=<key>, direct checkout URLs open externally, and the fallback is /sign-up.

Premium plugins

Premium plugins are configured in the premiumPlugins record and pluginBundle object in src/config/marketing-pricing.ts. Each plugin has a link created from a direct checkout URL or a provider variant ID:

  • CHECKOUT_URL_PLUGIN_AI_KIT — AI Kit plugin
  • CHECKOUT_URL_PLUGIN_CRM — CRM plugin
  • CHECKOUT_URL_PLUGIN_HELPDESK — Helpdesk plugin
  • CHECKOUT_URL_PLUGIN_EMAIL_MARKETING — Email Marketing plugin
  • CHECKOUT_URL_PLUGIN_BUNDLE — All plugins bundle (discounted)

When set, plugin cards on the pricing page and the /plugins page show purchase buttons. Without these env vars, buttons link to /#plugins.

Testimonials

export const testimonials: Testimonial[] = [
  {
    name: 'Alex Chen',
    role: 'Founder, StartupXYZ',
    content: 'Codapult saved me weeks of setup time.',
    initials: 'AC',
  },
  // ...add real customer quotes
];

Stats, modules, and comparison pages

The stats array powers the "by the numbers" section on the landing page. moduleCategories powers the module showcase. Comparison pages read from src/config/competitor-comparison.ts; edit or remove those entries so they match your product's real feature matrix and competitors.


Typed env var access

src/lib/config.ts provides a typed env object for reading environment variables in server code:

import { env } from '@/lib/config';

// Type-safe access with defaults
env.auth.provider; // 'better-auth' | 'kinde' | 'none'
env.paymentProvider; // 'stripe' | 'lemonsqueezy'
env.storageProvider; // 'local' | 's3' | 'r2'
env.notificationTransport; // 'poll' | 'sse' | 'ws'
env.vectorStoreProvider; // 'sqlite' | 'memory'
env.sso.product; // string — SSO product identifier
env.defaultMonthlyCredits; // number — monthly AI credits
env.stripe.connectFeePercent; // number — Stripe Connect fee
env.stripe.secretKey; // string
env.turso.url; // string

Important: Server-side code should use env.* for adapter/provider settings and appConfig.* for app identity (appUrl, serverUrl, appName, brand). Never read process.env directly for values available through these objects.

This file is hand-maintained. When adding a new environment variable, add a Zod field to the schema and a corresponding property to the env object in the same file.

For the full list of environment variables and their descriptions, see the Environment Variables reference.

Environment VariablesAuthentication