Skip to content

Commit

Permalink
feat(db-vercel-postgres): allow to use a local database using pg in…
Browse files Browse the repository at this point in the history
…stead of `@vercel/postgres` (#9771)

### What?
This PR allows you to use a local database when using
`vercelPostgresAdapter`. This adapter doesn't work with them because it
requires an SSL connection and Neon's WS proxy. Instead we fallback to
using pool from `pg` if `hostname` is either `127.0.0.1` or `localhost`.

If you still want to use `@vercel/postgres` even locally you can pass
`disableUsePgForLocalDatabase: true` here and you'd have to spin up the
DB with a special Neon's Docker Compose setup -
https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker

### Why?
Forcing people to use a cloud database locally isn't great. Not only
they are slow but also paid.

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
  • Loading branch information
r1tsuu and DanRibbens authored Dec 16, 2024
1 parent ed44ec0 commit 41167bf
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 2 deletions.
7 changes: 6 additions & 1 deletion docs/database/postgres.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export default buildConfig({
})
```

<Banner type="info">
<strong>Note:</strong>
If when using `vercelPostgresAdapter` your `process.env.POSTGRES_URL` or `pool.connectionString` points to a local database (e.g hostname has `localhost` or `127.0.0.1`) we use the `pg` module for pooling instead of `@vercel/postgres`. This is because `@vercel/postgres` doesn't work with local databases, if you want to disable that behavior, you can pass `forceUseVercelPostgres: true` to adapter's 'args and follow [Vercel guide](https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker) for a Docker Neon DB setup.
</Banner>

## Options

| Option | Description |
Expand Down Expand Up @@ -178,7 +183,7 @@ postgresAdapter({
})
```

Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.


### afterSchemaInit
Expand Down
23 changes: 22 additions & 1 deletion packages/db-vercel-postgres/src/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Connect } from 'payload'
import { pushDevSchema } from '@payloadcms/drizzle'
import { sql, VercelPool } from '@vercel/postgres'
import { drizzle } from 'drizzle-orm/node-postgres'
import pg from 'pg'

import type { VercelPostgresAdapter } from './types.js'

Expand All @@ -24,10 +25,30 @@ 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 (
!this.forceUseVercelPostgres &&
connectionString &&
['127.0.0.1', 'localhost'].includes(new URL(connectionString).hostname)
) {
client = new pg.Pool(
this.poolOptions ?? {
connectionString,
},
)
} else {
client = this.poolOptions ? new VercelPool(this.poolOptions) : sql
}

// Passed the poolOptions if provided,
// else have vercel/postgres detect the connection string from the environment
this.drizzle = drizzle({
client: this.poolOptions ? new VercelPool(this.poolOptions) : sql,
client,
logger,
schema: this.schema,
})
Expand Down
1 change: 1 addition & 0 deletions packages/db-vercel-postgres/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export function vercelPostgresAdapter(args: Args = {}): DatabaseAdapterObj<Verce
json: true,
},
fieldConstraints: {},
forceUseVercelPostgres: args.forceUseVercelPostgres ?? false,
idType: postgresIDType,
indexes: new Set<string>(),
initializing,
Expand Down
8 changes: 8 additions & 0 deletions packages/db-vercel-postgres/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ 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
*/
forceUseVercelPostgres?: boolean
idType?: 'serial' | 'uuid'
localesSuffix?: string
logger?: DrizzleConfig['logger']
Expand Down Expand Up @@ -58,6 +65,7 @@ export type Args = {
}

export type VercelPostgresAdapter = {
forceUseVercelPostgres?: boolean
pool?: VercelPool
poolOptions?: Args['pool']
} & BasePostgresAdapter
Expand Down

0 comments on commit 41167bf

Please sign in to comment.