Skip to content

Commit 4bd6006

Browse files
committed
Enhance environment configuration and database connection handling
- Implemented dynamic import for environment validation in next.config.js to avoid blocking initialization. - Updated prisma/schema.prisma to include a direct connection URL for Supabase, improving performance and connection management. - Modified src/env.js to add optional DIRECT_URL for environment variables. - Refactored db.ts to optimize Prisma client usage in serverless environments, ensuring connection reuse and graceful shutdown handling.
1 parent 69326cf commit 4bd6006

File tree

4 files changed

+56
-5
lines changed

4 files changed

+56
-5
lines changed

next.config.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
/**
22
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
33
* for Docker builds.
4+
*
5+
* Note: We use dynamic import here to avoid blocking Next.js initialization.
6+
* The env validation will happen when the module is actually used, not during config load.
47
*/
5-
await import("./src/env.js");
8+
if (!process.env.SKIP_ENV_VALIDATION) {
9+
// Use dynamic import to avoid blocking initialization
10+
import("./src/env.js").catch((err) => {
11+
console.error("Failed to load env validation:", err);
12+
});
13+
}
614

715
/** @type {import("next").NextConfig} */
816
const config = {

prisma/schema.prisma

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ generator client {
55
datasource db {
66
provider = "postgresql"
77
url = env("DATABASE_URL")
8+
// For Supabase + Vercel serverless optimization:
9+
// - DATABASE_URL: Use Supabase's connection pooling URL (Transaction mode)
10+
// Example: postgresql://user:pass@host:6543/db?pgbouncer=true
11+
// - DIRECT_URL: Use Supabase's direct connection URL (for migrations)
12+
// Example: postgresql://user:pass@host:5432/db
13+
// For local dev without Supabase, set DIRECT_URL to DATABASE_URL
14+
// This separation improves performance and prevents connection pool exhaustion
15+
directUrl = env("DIRECT_URL")
816
}
917

1018
model User {

src/env.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const env = createEnv({
88
*/
99
server: {
1010
DATABASE_URL: z.string().url(),
11+
DIRECT_URL: z.string().url().optional(),
1112
NODE_ENV: z
1213
.enum(["development", "test", "production"])
1314
.default("development"),
@@ -45,6 +46,7 @@ export const env = createEnv({
4546
*/
4647
runtimeEnv: {
4748
DATABASE_URL: process.env.DATABASE_URL,
49+
DIRECT_URL: process.env.DIRECT_URL,
4850
NODE_ENV: process.env.NODE_ENV,
4951
// NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
5052
// NEXTAUTH_URL: process.env.NEXTAUTH_URL,

src/server/db.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,49 @@ import { PrismaClient } from "@prisma/client";
22

33
import { env } from "@/env";
44

5-
const createPrismaClient = () =>
6-
new PrismaClient({
5+
const createPrismaClient = () => {
6+
const client = new PrismaClient({
77
log:
88
env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
99
});
1010

11+
// In serverless environments (Vercel), we want to avoid eager connection
12+
// Prisma will connect lazily on first query, which is better for cold starts
13+
// Don't call $connect() here - let Prisma handle connections on-demand
14+
15+
return client;
16+
};
17+
1118
const globalForPrisma = globalThis as unknown as {
1219
prisma: ReturnType<typeof createPrismaClient> | undefined;
1320
};
1421

15-
export const db = globalForPrisma.prisma ?? createPrismaClient();
22+
// Reuse Prisma client across invocations to optimize connection pooling
23+
// In Vercel serverless, the same container may handle multiple requests
24+
// Reusing the client prevents creating new connections for each request
25+
export const db =
26+
globalForPrisma.prisma ?? createPrismaClient();
1627

17-
if (env.NODE_ENV !== "production") globalForPrisma.prisma = db;
28+
// Store in globalThis for reuse across all environments
29+
// This is especially important in serverless where the same container
30+
// may handle multiple requests, allowing connection reuse
31+
if (!globalForPrisma.prisma) {
32+
globalForPrisma.prisma = db;
33+
}
34+
35+
// Graceful shutdown handling
36+
if (typeof process !== "undefined") {
37+
process.on("beforeExit", async () => {
38+
await db.$disconnect();
39+
});
40+
41+
process.on("SIGINT", async () => {
42+
await db.$disconnect();
43+
process.exit(0);
44+
});
45+
46+
process.on("SIGTERM", async () => {
47+
await db.$disconnect();
48+
process.exit(0);
49+
});
50+
}

0 commit comments

Comments
 (0)