Application Configuration
A deep dive into src/config/index.ts: what each config item does, where it takes effect, and suggested change patterns.
src/config/index.ts is MuseMVP's runtime configuration entry point. It centrally manages i18n, auth behavior, page switches, storage, payments, AI, and analytics.
If you want to "change product behavior," this file is usually your first stop.
What This Page Covers
This page only covers code-level configuration in src/config/index.ts. For secrets and environment variables (such as database, OAuth, and payment gateway API keys), see /docs/quick-build/environment-variables.
Configuration Guide
i18n: Internationalization
Key fields:
i18n.enabledi18n.locales.en|zh(appName/summary/description/keywords/docsAlias/headerMenuMap/footerConfig)i18n.defaultLocalei18n.defaultCurrencyi18n.localePrefixi18n.localeCookieName
Practical impact:
docsAliasis used as the docs page title suffix (for example,xxx | Docs).headerMenuMapis reused by navigation and custom routes.localePrefixaffects next-intl routing behavior and the language-hiding strategy of docs sources.
Suggestion When Updating Copy
Update en and zh in sync to avoid mismatches between bilingual navigation and footer text.
users: New User Onboarding Redirect and Billing Master Switch
Key field:
users.enableSetup
Current behavior:
enableSetup=true: newly registered users (logged-in users who have not completed onboarding) are redirected to/setup.
auth: Registration Methods and Session Lifecycle
Key fields:
auth.gates.allowRegisterauth.gates.allowSocialSignInauth.gates.allowPasswordSignInauth.gates.allowTwoFactorAuthauth.lifecycle.redirectAfterLoginauth.lifecycle.redirectAfterSignOutauth.lifecycle.redirectWhenSessionExpiredauth.lifecycle.sessionTtlSeconds
Behavior highlights:
- When
allowRegister=false,/auth/registerredirects to/auth/login. allowPasswordSignInandallowSocialSignInmainly control frontend entry visibility.allowTwoFactorAuthmainly controls whether the 2FA block is shown on the settings page.sessionTtlSecondsis written directly into Better-Authsession.expiresIn.
Easy-to-Misunderstand Point
allowTwoFactorAuth is not a backend plugin master switch. The 2FA plugin is still registered; this flag mainly controls whether the frontend exposes the entry point.
mails: Sender Identity and Brand Logo
Key fields:
mails.frommails.links.logo
Behavior highlights:
- If
mails.fromis only an email address, it will be automatically assembled into the format"AppName" <email@...>at send time. mails.links.logois used for the logo in email templates. By default it usespublic/icon.pngunder the project root, and you can also switch to a custom external image URL with faster access.
ui: Themes, Page Switches, Navigation, and Footer
ui is the most frequently changed section, so it is best understood in blocks.
ui: {
enabledThemes: ["light", "dark"],
defaultTheme: "dark",
saas: { enabled: true, useSidebarLayout: true, cookieInfo: { showBox: true } },
features: { enabled: true },
docs: { enabled: true },
legal: {
enabled: true,
allowMap: [
{ type: "privacy", enabled: true },
{ type: "terms", enabled: true },
{ type: "behavior", enabled: false },
],
},
changelog: { enabled: true },
blog: { enabled: true },
contactForm: {
enabled: true,
to: "support@musemvp.com",
subject: "MuseMVP contact form message",
},
}Behavior highlights:
ui.saas.enabled=falsecloses entries to both auth and saas areas (related layouts redirect directly to home).ui.docs/blog/changelog/contactForm/featuresaffects both nav visibility and corresponding page access.ui.legal.enabledcontrols the legal pages master switch;allowMapmainly affects legal link display in footer/auth pages.- In
customRoutes, items withenabled && !externalare automatically added to sitemap. - For
customRoutes, the final title prefersheaderMenuMap[path], then falls back tolabel. footerConfig.socialIcon.github.hrefis also used by docs pages to generate the GitHub source link.
Two Common Pitfalls
allowMap is not a legal route allowlist; it mainly controls link visibility.
Also, when ui.docs.enabled=false, the current sitemap implementation still generates docs URLs. If you need strict consistency, also update src/app/sitemap.ts.
storage: Cloudflare R2
Key fields:
storage.meta.S3_ACCESS_KEY_IDstorage.meta.S3_SECRET_ACCESS_KEYstorage.meta.S3_ENDPOINTstorage.meta.S3_REGION(default:auto)storage.bucketNames.avatars(default:musemvp-com)storage.proxyUrls.avatarsFile
Behavior highlights:
- The upload API checks
S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY / S3_ENDPOINT; missing values return an error. NEXT_PUBLIC_AVATARS_PROXY_URLremoves a trailing/before URL composition.- If the
avatarsbucket name is not configured, it falls back to the defaultmusemvp-com.
ai: Chat Model Selection
Key fields:
ai.enabledai.chatModel
Behavior highlights:
ai.enabled=falsehides AI Chat items from account navigation, redirects/app/aichatto/app, and makes/api/aichat/**return404.- The backend AI Chat route reads
config.ai.chatModeldirectly asMODEL_ID; the default model isgemini-3-pro-preview. - In most cases, changing models only requires updating this one field (as long as the corresponding provider key is configured).
payments: Billing Master Switch and Product Catalog Mapping
Key fields:
payments.enableBillingpayments.enableFreepayments.enableEnterprisepayments.productCatalog
productCatalog productId resolution priority (using monthly Pro as an example):
NEXT_PUBLIC_MUSE_PRICE_PRO_MONTHLY_ID
-> NEXT_PUBLIC_MUSE_CREEM_PRICE_PRO_MONTHLY_ID
-> NEXT_PUBLIC_MUSE_STRIPE_PRICE_PRO_MONTHLY_ID
-> ""Behavior highlights:
productCatalog.*.gatewayProductIdsis used when creating checkout sessions; missing values throw errors directly.- In
pricing-desc-usage.ts, only price items with non-emptyproductIdare included in plan display. pricing-desc-usage.tsalso supports an optionaloriginalAmountfield for compare-at pricing display. It affects only the pricing UI; checkout still usesamount.enableBilling=falsedisables the pricing entry and related billing flow branches.
Important Boundary
The default gateway selection (MUSE_BILLING_DEFAULT_GATEWAY) and gateway API keys are in environment variables, not in config/index.ts.
analytics: Analytics Script Injection
Key fields:
analytics.googleAnalyticsIdanalytics.baiduTongjiId
Behavior highlights:
- Analytics scripts are injected only in non-development environments.
- If an ID is empty, the corresponding script is not rendered.
Post-Change Verification Checklist
pnpm type-check
pnpm buildConfirm Header / Footer copy renders correctly in both en and zh.
Confirm visibility for docs/blog/legal/changelog/contact/features matches the switch settings.
If ai.enabled=false, confirm AI Chat no longer appears in the sidebar/profile menu, /app/aichat redirects, and /api/aichat/** is inaccessible.
Confirm login/register/sign-out redirects match auth.lifecycle config.
Confirm the pricing page only shows plans with configured productId.
If originalAmount is configured, confirm the pricing card shows the strikethrough original price while checkout still uses amount.
Confirm avatar upload and asset access match storage config (bucket name/proxy URL).