Missing STRIPE_SECRET_KEY environment variable

I put a site online with Turbo repo on which I have a subscription system with Stripe

Locally, everything is working properly, I have no errors, my environment variables are well defined, my subscriptions are working well, etc.

As soon as I want to put my site into production, I get the error Error: Missing STRIPE_SECRET_KEY environment variable.

I have this key in my environment variables and it has a value.

I currently have the following error: live:build: Error: Missing STRIPE_SECRET_KEY environment variable live:build: at 25070 (/vercel/path0/apps/live/.next/server/app/api/webhook/stripe/route.js:1:88381) live:build: at t (/vercel/path0/apps/live/.next/server/webpack-runtime.js:1:143) live:build: at /vercel/path0/apps/live/.next/server/app/api/webhook/stripe/route.js:1:131928 live:build: at t.X (/vercel/path0/apps/live/.next/server/webpack-runtime.js:1:1312) live:build: at /vercel/path0/apps/live/.next/server/app/api/webhook/stripe/route.js:1:131891 live:build: at Object.<anonymous> (/vercel/path0/apps/live/.next/server/app/api/webhook/stripe/route.js:1:131964) live:build: at Module._compile (node:internal/modules/cjs/loader:1562:14) live:build: at Object..js (node:internal/modules/cjs/loader:1699:10) live:build: at Module.load (node:internal/modules/cjs/loader:1313:32) live:build: at Function._load (node:internal/modules/cjs/loader:1123:12) live:build: live:build: > Build error occurred live:build: Error: Failed to collect page data for /api/webhook/stripe live:build: at /vercel/path0/node_modules/next/dist/build/utils.js:1268:15 live:build: at process.processTicksAndRejections (node:internal/process/task_queues:105:5) { live:build: type: 'Error' live:build: }

I would like this variable to be read and functional as it is already provided in all my environments.

To make my stripe work, I have the following configuration:

actions.ts : `“use server”;

import { UserRole } from “@prisma/client”;
import { prisma } from “@repo/db”;
import { redirect } from “next/navigation”;
import { addUserStripeCustomerId } from “…/actions/user-informations”;
import { stripe } from “./stripe”;
import stripeConfig from “./stripe.config”;

export const createStripeCheckoutSession = async (
customerId: string,
priceId: string,
userId: string
) => {
try {
const session = await stripe.checkout.sessions.create({
customer: customerId,
line_items: [
{
price: priceId,
quantity: 1,
},
],
mode: “subscription”,
success_url: ${stripeConfig.url.success},
cancel_url: ${stripeConfig.url.cancel},
metadata: {
userId,
},
});

return session;

} catch (error) {
console.error(error);

return null;

}
};

export const createStripeCustomer = async (
userId: string,
name: string,
email: string
) => {
try {
const customer = await stripe.customers.create({
email,
name,
});

const res = await addUserStripeCustomerId(userId, customer.id);

if (!res) {
  throw new Error("Impossible de sauvegarder le customer id");
}

return customer;

} catch (error) {
console.error(error);

return null;

}
};

export const getUserFromPayment = async (paymentIntentId: string) => {
try {
// Récupérer le Payment Intent
const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);

// Accéder aux métadonnées pour trouver l'utilisateur
const userId = paymentIntent.metadata?.userId;

console.log("Utilisateur identifié :", userId);

return userId;

} catch (error) {
console.error(“Erreur lors de la récupération du paiement :”, error);
return null;
}
};

export const getUserFromCustomerId = async (customerId: unknown) => {
if (typeof customerId !== “string”) {
console.error(“Le customerId n’est pas une string”);
return null;
}

try {
const customer = await prisma.user.findFirst({
where: {
stripeCustomerId: customerId,
},
});

return customer;

} catch (error) {
console.error(“Erreur lors de la récupération du customer :”, error);
return null;
}
};

export const createBillingPortalSession = async (
customerId: string,
role: UserRole
) => {
const stripeSession = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: ${stripeConfig.billing.return_url},
});

if (!stripeSession) throw new Error(“Impossible de créer la session”);

redirect(stripeSession.url);
};```

stripe.ts: `import Stripe from “stripe”;

if (!process.env.STRIPE_SECRET_KEY) {
throw new Error(“Missing STRIPE_SECRET_KEY environment variable”);
}

export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: “2024-12-18.acacia”,
});`

role-manager.ts: `“use server”;

import { UserRole } from “@prisma/client”;
import Stripe from “stripe”;
import { downgradeUserRole, upgradeUserRole } from “…/actions/user-role”;
import { getUserFromCustomerId } from “./actions”;

export const checkoutSessionCompleted = async (event: Stripe.Event) => {
const session = event.data.object as Stripe.Checkout.Session;
const stripeCustomerId = session.customer;
const user = await getUserFromCustomerId(stripeCustomerId);

if (!user) {
console.error(“User not found for stripe customer id”, stripeCustomerId);
return;
}

await upgradeUserRole(user.id, UserRole.AGENT);

return;
};

export const invoicePaid = async (event: Stripe.Event) => {
const invoice = event.data.object as Stripe.Invoice;
const stripeCustomerId = invoice.customer;
const user = await getUserFromCustomerId(stripeCustomerId);

if (!user) {
console.error(“User not found for stripe customer id”, stripeCustomerId);
return;
}

await upgradeUserRole(user.id, UserRole.AGENT);

return;
};

export const invoicePaymentFailed = async (event: Stripe.Event) => {
const invoice = event.data.object as Stripe.Invoice;
const stripeCustomerId = invoice.customer;
const user = await getUserFromCustomerId(stripeCustomerId);

if (!user) {
console.error(“User not found for stripe customer id”, stripeCustomerId);
return;
}

await downgradeUserRole(user.id);

return;
};

export const subscriptionDeleted = async (event: Stripe.Event) => {
const subscription = event.data.object as Stripe.Subscription;
const stripeCustomerId = subscription.customer;
const user = await getUserFromCustomerId(stripeCustomerId);

if (!user) {
console.error(“User not found for stripe customer id”, stripeCustomerId);
return;
}

await downgradeUserRole(user.id);

return;
};`

And my API route at “api/webhook/stripe/route.ts” : `“use server”;

import {
checkoutSessionCompleted,
invoicePaid,
invoicePaymentFailed,
subscriptionDeleted,
} from “@repo/lib/stripe/role-management”;
import { NextRequest, NextResponse } from “next/server”;
import Stripe from “stripe”;

export const POST = async (req: NextRequest) => {
const body = (await req.json()) as Stripe.Event;

switch (body.type) {
case “checkout.session.completed”: {
await checkoutSessionCompleted(body);
break;
}
case “invoice.paid”: {
await invoicePaid(body);
break;
}
case “invoice.payment_failed”: {
await invoicePaymentFailed(body);
break;
}
case “customer.subscription.deleted”: {
await subscriptionDeleted(body);
break;
}
default: {
console.log(“Unhandled event type”, body.type);
break;
}
}

return NextResponse.json({ status: 200, ok: true });
};`

In local all it’s working well but I encounter error when I’m deploying this code

I’m using NextJS with the app router, node 22 and stripe 17.5

Hello,

If you are using Turborepo 2.x, you will need to make sure the Environment variable also available in turbo.json to cache properly and available in build time: Using environment variables | Turborepo

Sorry, I forgot to mention that.
Here you can find my current turbo.json config:
`{
“$schema”: “https://turbo.build/schema.json”,

"tasks": {
  "pipeline": {
    "env": ["STRIPE_SECRET_KEY"]
  },
  "build": {
    "dependsOn": ["^build", "^db:generate"],
    "inputs": ["$TURBO_DEFAULT$", ".env*"],
    "outputs": [".next/**", "!.next/cache/**"]
  },
  "lint": {
    "dependsOn": ["^lint"]
  },
  "dev": {
    "dependsOn": ["^db:generate"],
    "cache": false,
    "persistent": true
  },
  "db:generate": {
    "cache": false
  },
  "db:push": {
    "cache": false
  }
}

}
`

It looks like the pipeline key is nested into the tasks key, meaning that pipeline signifies a task. You probably meant to put the "env": ["STRIPE_SECRET_KEY"] line into the build task.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.