diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index 643026cd70a..54eca84d035 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -74,8 +74,8 @@ "renamePredefinedMigrations": "node --no-deprecation --import @swc-node/register/esm-register ./scripts/renamePredefinedMigrations.ts" }, "dependencies": { + "@neondatabase/serverless": "^1.0.2", "@payloadcms/drizzle": "workspace:*", - "@vercel/postgres": "^0.10.0", "console-table-printer": "2.12.1", "drizzle-kit": "0.31.7", "drizzle-orm": "0.45.2", diff --git a/packages/db-vercel-postgres/src/connect.ts b/packages/db-vercel-postgres/src/connect.ts index 33780f096ff..f06fc428395 100644 --- a/packages/db-vercel-postgres/src/connect.ts +++ b/packages/db-vercel-postgres/src/connect.ts @@ -1,9 +1,10 @@ -import type { DrizzleAdapter } from '@payloadcms/drizzle/types' +import type { DrizzleAdapter } from '@payloadcms/drizzle' import type { Connect, Migration } from 'payload' +import { Pool as NeonPool } from '@neondatabase/serverless' import { pushDevSchema } from '@payloadcms/drizzle' -import { sql, VercelPool } from '@vercel/postgres' -import { drizzle } from 'drizzle-orm/node-postgres' +import { drizzle as drizzleNeon } from 'drizzle-orm/neon-serverless' +import { drizzle as drizzlePg } from 'drizzle-orm/node-postgres' import { withReplicas } from 'drizzle-orm/pg-core' import pg from 'pg' @@ -20,33 +21,26 @@ export const connect: Connect = async function connect( try { const logger = this.logger || false - let client: pg.Pool | VercelPool - const connectionString = this.poolOptions?.connectionString ?? process.env.POSTGRES_URL // Use non-vercel postgres for local database - if ( + const useLocalPg = !this.forceUseVercelPostgres && connectionString && ['127.0.0.1', 'localhost'].includes(new URL(connectionString).hostname) - ) { - client = new pg.Pool( + + if (useLocalPg) { + const client = new pg.Pool( this.poolOptions ?? { connectionString, }, ) + this.drizzle = drizzlePg({ client, logger, schema: this.schema }) } else { - client = this.poolOptions ? new VercelPool(this.poolOptions) : sql + const client = new NeonPool(this.poolOptions ?? { connectionString }) + this.drizzle = drizzleNeon({ client, logger, schema: this.schema }) } - // Passed the poolOptions if provided, - // else have vercel/postgres detect the connection string from the environment - this.drizzle = drizzle({ - client: client as pg.Pool, - logger, - schema: this.schema, - }) - if (this.readReplicaOptions) { this.primaryDrizzle = this.drizzle as any const readReplicas = this.readReplicaOptions.map((connectionString) => { @@ -54,8 +48,12 @@ export const connect: Connect = async function connect( ...this.poolOptions, connectionString, } - const pool = new VercelPool(options) - return drizzle({ client: pool as unknown as pg.Pool, logger, schema: this.schema }) + if (useLocalPg) { + const pool = new pg.Pool(options) + return drizzlePg({ client: pool, logger, schema: this.schema }) + } + const pool = new NeonPool(options) + return drizzleNeon({ client: pool, logger, schema: this.schema }) }) const myReplicas = withReplicas(this.drizzle, readReplicas as any) this.drizzle = myReplicas diff --git a/packages/db-vercel-postgres/src/types.ts b/packages/db-vercel-postgres/src/types.ts index 5940582dbe2..386e78e1cd2 100644 --- a/packages/db-vercel-postgres/src/types.ts +++ b/packages/db-vercel-postgres/src/types.ts @@ -1,15 +1,14 @@ +import type { Pool, PoolConfig } from '@neondatabase/serverless' import type { BasePostgresAdapter, GenericEnum, MigrateDownArgs, MigrateUpArgs, - PostgresDB, PostgresSchemaHook, } from '@payloadcms/drizzle/postgres' import type { DrizzleAdapter } from '@payloadcms/drizzle/types' -import type { VercelPool, VercelPostgresPoolConfig } from '@vercel/postgres' import type { DrizzleConfig } from 'drizzle-orm' -import type { NodePgDatabase } from 'drizzle-orm/node-postgres' +import type { NeonDatabase } from 'drizzle-orm/neon-serverless' import type { PgSchema, PgTableFn, PgTransactionConfig } from 'drizzle-orm/pg-core' export type Args = { @@ -45,10 +44,8 @@ export type Args = { disableCreateDatabase?: boolean extensions?: string[] /** - * By default, we connect to a local database using the `pg` module instead of `@vercel/postgres`. - * This is because `@vercel/postgres` doesn't work with local databases. - * If you still want to use `@vercel/postgres` even locally you can pass `true` here - * and you'd to spin up the database with a special Neon's Docker Compose setup - https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker + * By default, we connect to a local database using the `pg` module instead of `@neondatabase/serverless`. + * If you still want to use `@neondatabase/serverless` even locally you can pass `true` here. */ forceUseVercelPostgres?: boolean /** Generated schema from payload generate:db-schema file path */ @@ -58,10 +55,10 @@ export type Args = { logger?: DrizzleConfig['logger'] migrationDir?: string /** - * Optional pool configuration for Vercel Postgres - * If not provided, vercel/postgres will attempt to use the Vercel environment variables + * Optional pool configuration + * If not provided, will attempt to use the Vercel/Neon environment variables */ - pool?: VercelPostgresPoolConfig + pool?: PoolConfig prodMigrations?: { down: (args: MigrateDownArgs) => Promise name: string @@ -96,12 +93,12 @@ type ResolveSchemaType = 'schema' extends keyof T ? T['schema'] : GeneratedDatabaseSchema['schemaUntyped'] -type Drizzle = NodePgDatabase> +type Drizzle = NeonDatabase> export type VercelPostgresAdapter = { drizzle: Drizzle forceUseVercelPostgres?: boolean - pool?: VercelPool + pool?: Pool poolOptions?: Args['pool'] } & BasePostgresAdapter @@ -126,7 +123,7 @@ declare module 'payload' { localesSuffix?: string logger: DrizzleConfig['logger'] pgSchema?: { table: PgTableFn } | PgSchema - pool: VercelPool + pool: Pool poolOptions: Args['pool'] prodMigrations?: { down: (args: MigrateDownArgs) => Promise diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 985df0a40fb..59d2542b55d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,7 +114,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: 0.44.7 - version: 0.44.7(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.16.3) + version: 0.44.7(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.16.3) escape-html: specifier: ^1.0.3 version: 1.0.3 @@ -314,7 +314,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: 0.45.2 - version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) + version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) prompts: specifier: 2.4.2 version: 2.4.2 @@ -388,7 +388,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: 0.45.2 - version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) + version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) pg: specifier: 8.20.0 version: 8.20.0 @@ -434,7 +434,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: 0.45.2 - version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) + version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) prompts: specifier: 2.4.2 version: 2.4.2 @@ -460,12 +460,12 @@ importers: packages/db-vercel-postgres: dependencies: + '@neondatabase/serverless': + specifier: ^1.0.2 + version: 1.0.2 '@payloadcms/drizzle': specifier: workspace:* version: link:../drizzle - '@vercel/postgres': - specifier: ^0.10.0 - version: 0.10.0(utf-8-validate@6.0.6) console-table-printer: specifier: 2.12.1 version: 2.12.1 @@ -474,7 +474,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: 0.45.2 - version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) + version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) pg: specifier: 8.20.0 version: 8.20.0 @@ -517,7 +517,7 @@ importers: version: 2.0.3 drizzle-orm: specifier: 0.45.2 - version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) + version: 0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0) prompts: specifier: 2.4.2 version: 2.4.2 @@ -2489,7 +2489,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: 0.44.7 - version: 0.44.7(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.16.3) + version: 0.44.7(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.16.3) escape-html: specifier: 1.0.3 version: 1.0.3 @@ -5563,6 +5563,10 @@ packages: '@neondatabase/serverless@0.9.5': resolution: {integrity: sha512-siFas6gItqv6wD/pZnvdu34wEqgG3nSE6zWZdq5j2DEsa+VvX8i/5HXJOo06qrw5axPXn+lGCxeR+NLaSPIXug==} + '@neondatabase/serverless@1.0.2': + resolution: {integrity: sha512-I5sbpSIAHiB+b6UttofhrN/UJXII+4tZPAq1qugzwCwLIL8EZLV7F/JyHUrEIiGgQpEXzpnjlJ+zwcEhheGvCw==} + engines: {node: '>=19.0.0'} + '@next/bundle-analyzer@16.2.2': resolution: {integrity: sha512-wIpZBHyCv1y+y0dnFmqQFlpX91V94Z7RKnpu1TRP0BRaWB/1M74Iqxa9IJ8lzSO0FyTqKldgDHoQJJmn8F+gIA==} @@ -18532,6 +18536,12 @@ snapshots: '@neondatabase/serverless@0.9.5': dependencies: '@types/pg': 8.11.6 + optional: true + + '@neondatabase/serverless@1.0.2': + dependencies: + '@types/node': 22.19.9 + '@types/pg': 8.20.0 '@next/bundle-analyzer@16.2.2(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: @@ -21410,6 +21420,7 @@ snapshots: '@types/node': 22.19.9 pg-protocol: 1.13.0 pg-types: 4.1.0 + optional: true '@types/pg@8.20.0': dependencies: @@ -21761,6 +21772,7 @@ snapshots: ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - utf-8-validate + optional: true '@vitejs/plugin-react@4.5.2(vite@7.3.2(@types/node@22.19.9)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.99.0)(sass@1.99.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: @@ -22616,6 +22628,7 @@ snapshots: bufferutil@4.1.0: dependencies: node-gyp-build: 4.8.4 + optional: true builtins@5.1.0: dependencies: @@ -23248,10 +23261,11 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.44.7(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.16.3): + drizzle-orm@0.44.7(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.16.3): optionalDependencies: '@cloudflare/workers-types': 4.20260218.0 '@libsql/client': 0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@neondatabase/serverless': 1.0.2 '@opentelemetry/api': 1.9.1 '@types/better-sqlite3': 7.6.13 '@types/pg': 8.20.0 @@ -23259,10 +23273,11 @@ snapshots: better-sqlite3: 11.10.0 pg: 8.16.3 - drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0): + drizzle-orm@0.45.2(@cloudflare/workers-types@4.20260218.0)(@libsql/client@0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@neondatabase/serverless@1.0.2)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(@vercel/postgres@0.10.0(utf-8-validate@6.0.6))(better-sqlite3@11.10.0)(pg@8.20.0): optionalDependencies: '@cloudflare/workers-types': 4.20260218.0 '@libsql/client': 0.14.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@neondatabase/serverless': 1.0.2 '@opentelemetry/api': 1.9.1 '@types/better-sqlite3': 7.6.13 '@types/pg': 8.20.0 @@ -26456,7 +26471,8 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 - node-gyp-build@4.8.4: {} + node-gyp-build@4.8.4: + optional: true node-gyp@12.2.0: dependencies: @@ -26569,7 +26585,8 @@ snapshots: obliterator@1.6.1: {} - obuf@1.1.2: {} + obuf@1.1.2: + optional: true obug@2.1.1: {} @@ -26774,7 +26791,8 @@ snapshots: pg-int8@1.0.1: {} - pg-numeric@1.0.2: {} + pg-numeric@1.0.2: + optional: true pg-pool@3.13.0(pg@8.16.3): dependencies: @@ -26803,6 +26821,7 @@ snapshots: postgres-date: 2.1.0 postgres-interval: 3.0.0 postgres-range: 1.1.4 + optional: true pg@8.16.3: dependencies: @@ -26940,25 +26959,30 @@ snapshots: postgres-array@2.0.0: {} - postgres-array@3.0.4: {} + postgres-array@3.0.4: + optional: true postgres-bytea@1.0.1: {} postgres-bytea@3.0.0: dependencies: obuf: 1.1.2 + optional: true postgres-date@1.0.7: {} - postgres-date@2.1.0: {} + postgres-date@2.1.0: + optional: true postgres-interval@1.2.0: dependencies: xtend: 4.0.2 - postgres-interval@3.0.0: {} + postgres-interval@3.0.0: + optional: true - postgres-range@1.1.4: {} + postgres-range@1.1.4: + optional: true prebuild-install@7.1.3: dependencies: