Deployment Issues
If the template works locally but breaks after deploy, the problem is usually not “Nuxt does not work in production”. It is usually one of these:
- the deployed env differs from local
- the public domain and auth domain are misaligned
- passkey RP ID still points at
localhost - the server has too little memory for stable build or runtime behavior
Problem: Production Boots Differently Than Local
Section titled “Problem: Production Boots Differently Than Local”This is common when .env.example placeholders were copied into the deployed
environment without being cleaned up.
Examples:
- fake Stripe key enables real Stripe code paths
- fake OpenAI key enables real OpenAI code paths
- production mail driver is set to
resend, but the API key is missing
Do not compare only the files in Git. Compare the real deployed environment variables value by value.
Problem: The App Starts In Production, So You Assume The Deployment Is Fine
Section titled “Problem: The App Starts In Production, So You Assume The Deployment Is Fine”That is not a safe conclusion in this template.
Startup env validation catches some shape errors, but it does not prove:
- Stripe is usable
- AI requests will succeed
- SMTP or Resend can actually deliver mail
- passkeys are bound to the correct relying party
Treat deploy validation as a feature-by-feature smoke test, not just a boot test.
Problem: Auth, OAuth, Or Email Links Point To The Wrong Domain
Section titled “Problem: Auth, OAuth, Or Email Links Point To The Wrong Domain”Your deployed public URLs must agree with each other.
Minimum checks:
NUXT_PUBLIC_SITE_URLBETTER_AUTH_URL- OAuth callback registrations in provider consoles
- Stripe success/cancel return URLs if you override them
If the app mixes localhost, preview domains, IP addresses, and the final
production domain, you can get broken cookies, wrong callback redirects, or
invalid verification links.
Problem: Passkeys Fail Only In Production
Section titled “Problem: Passkeys Fail Only In Production”This is usually a relying-party problem.
If BETTER_AUTH_PASSKEY_RP_ID is still set to localhost, the explicit RP ID
overrides automatic hostname resolution and production passkey flows can fail.
- set
BETTER_AUTH_URLandNUXT_PUBLIC_SITE_URLto the real production origin - set
BETTER_AUTH_PASSKEY_RP_IDto the real hostname, or remove it entirely - redeploy and test passkey registration again on the final domain
Problem: Coolify Build Or Runtime Feels Unstable
Section titled “Problem: Coolify Build Or Runtime Feels Unstable”Based on your prior deployment test, treat 3.5 GB memory as the safer floor
for Coolify.
Below that, you are more likely to see:
- builds getting killed
- unstable runtime behavior under load
- provider-heavy flows failing in ways that are hard to reproduce locally
Problem: Billing Works Locally But Not After Deploy
Section titled “Problem: Billing Works Locally But Not After Deploy”Production billing usually fails because one of these is wrong:
- real Stripe secret key missing or invalid
- webhook secret not aligned with the production endpoint
- production price IDs missing
- webhook endpoint not reachable from Stripe
Debug in this order:
- create one checkout session
- confirm checkout completes in Stripe
- confirm the webhook fires
- confirm local subscription state updates
Release-Baseline Check
Section titled “Release-Baseline Check”Before blaming the deployment platform, verify the site the same way this repo expects:
pnpm typecheckpnpm buildnpm run typechecknpm run buildyarn typecheckyarn buildIf the issue is route or rendering related, validate the built output with preview as well:
pnpm previewnpm run previewyarn previewDo not treat the development server as the final source of truth for deployed behavior.