CodeIssuesPull RequestsActionsSecurityInsights
✨ AI
More
Settings

Fix Vercel build — Stripe lazy init #3993

Merged⚡ AI-generatedXSccantynz wants to mergeclaude/fix-vercel-buildmainopened Mar 27, 2026
4 changed files+26−13
Modifiedapp/api/stripe/checkout/route.js+3−3View fileUnifiedSplit
99 */
1010import { NextResponse } from 'next/server'
1111import { sql } from '@vercel/postgres'
12import { stripe, PRICE_IDS, APP_URL } from '../../../../lib/stripe'
12import { getStripe, PRICE_IDS, APP_URL } from '../../../../lib/stripe'
1313import { authenticate, initDb } from '../../../../lib/db'
1414
1515export async function POST(request) {
3030 // Reuse existing Stripe customer if they've paid before
3131 let customerId = user.stripe_customer_id
3232 if (!customerId) {
33 const customer = await stripe.customers.create({
33 const customer = await getStripe().customers.create({
3434 email: user.email,
3535 metadata: { user_id: user.user_id },
3636 })
3838 await sql`UPDATE users SET stripe_customer_id = ${customerId} WHERE id = ${user.user_id}`
3939 }
4040
41 const session = await stripe.checkout.sessions.create({
41 const session = await getStripe().checkout.sessions.create({
4242 customer: customerId,
4343 mode: 'subscription',
4444 line_items: [{ price: priceId, quantity: 1 }],
Modifiedapp/api/stripe/portal/route.js+2−2View fileUnifiedSplit
1111 * Returns: { url: "https://billing.stripe.com/..." }
1212 */
1313import { NextResponse } from 'next/server'
14import { stripe, APP_URL } from '../../../../lib/stripe'
14import { getStripe, APP_URL } from '../../../../lib/stripe'
1515import { authenticate, initDb } from '../../../../lib/db'
1616
1717export async function POST(request) {
2626 return NextResponse.json({ error: 'No subscription found. Choose a plan first.' }, { status: 400 })
2727 }
2828
29 const session = await stripe.billingPortal.sessions.create({
29 const session = await getStripe().billingPortal.sessions.create({
3030 customer: user.stripe_customer_id,
3131 return_url: `${APP_URL}/pricing`,
3232 })
Modifiedapp/api/stripe/webhook/route.js+3−3View fileUnifiedSplit
99 */
1010import { NextResponse } from 'next/server'
1111import { sql } from '@vercel/postgres'
12import { stripe } from '../../../../lib/stripe'
12import { getStripe } from '../../../../lib/stripe'
1313import { initDb } from '../../../../lib/db'
1414
1515// Stripe needs the raw body to verify the webhook signature
2929
3030 let event
3131 try {
32 event = stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET)
32 event = getStripe().webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET)
3333 } catch (err) {
3434 console.error('Webhook signature failed:', err.message)
3535 return NextResponse.json({ error: 'Invalid signature' }, { status: 400 })
7979
8080async function activatePlan(customerId) {
8181 // Get the active subscription to determine plan
82 const subscriptions = await stripe.subscriptions.list({
82 const subscriptions = await getStripe().subscriptions.list({
8383 customer: customerId,
8484 status: 'active',
8585 limit: 1,
Modifiedlib/stripe.js+18−5View fileUnifiedSplit
1212 */
1313import Stripe from 'stripe'
1414
15if (!process.env.STRIPE_SECRET_KEY) {
16 throw new Error('STRIPE_SECRET_KEY is required. Add it to your environment variables.')
15// Don't throw at import time — this crashes the Next.js build.
16// Instead, create a lazy getter that throws only when actually used.
17let _stripe = null
18
19export function getStripe() {
20 if (!_stripe) {
21 if (!process.env.STRIPE_SECRET_KEY) {
22 throw new Error('STRIPE_SECRET_KEY is required. Add it to your Vercel environment variables.')
23 }
24 _stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
25 apiVersion: '2024-12-18.acacia',
26 })
27 }
28 return _stripe
1729}
1830
19export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
20 apiVersion: '2024-12-18.acacia',
21})
31// Keep backward compat — but won't crash at build time
32export const stripe = typeof process !== 'undefined' && process.env.STRIPE_SECRET_KEY
33 ? new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2024-12-18.acacia' })
34 : null
2235
2336export const PRICE_IDS = {
2437 pro_monthly: process.env.STRIPE_PRO_PRICE_ID,
2538
c comment · e edit title · m merge · a approve · r request changes · ? shortcuts