Deploying Next.js w/ Drizzle on Vercel with Turborepo

Jjeanhdev5/12/2023
I have a turborepo with Next.js using drizzle-orm as a shared package.

A bit of context - I'm using a monorepo with drizzle and share the tables, types and schemas across all my apps by having a shared packages/database library - that my Next.js app is consuming.

One issue I've had is that in order to get drizzle-orm working in my monorepo I've had to install it globally ie. in my root level package.json.

My package.json at the root level looks like this at the moment:

{
  "name": ...,
  "private": true,
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
  },
  "devDependencies": {
    "@ianvs/prettier-plugin-sort-imports": "^3.7.2",
    "@types/pg": "^8.6.6",
    "drizzle-kit": "^0.17.5",
    "eslint": "^7.32.0",
    "prettier": "^2.8.7",
    "turbo": "latest"
  },
  "dependencies": {
    "drizzle-orm": "^0.25.4",
    "drizzle-zod": "^0.4.1",
    "pg": "^8.10.0",
    "pg-native": "^3.0.1",
    "zod": "^3.21.4"
  },
  "workspaces": [
    "apps/*",
    "packages/*"
  ]
}

Note that all of the packages above are not in either my packages/database or apps/next dependencies.
My Next.js app consume my database library like this in the apps/next application's package.json
"database": "1.0.0"
Jjeanhdev5/12/2023
I've had no error in local development. But when trying to deploy to Vercel I've had this error;
.../libpq@1.8.12/node_modules/libpq install: which: no pg_config in (/vercel/path0/node_modules/.pnpm/libpq@1.8.12/node_modules/libpq/node_modules/.bin:/vercel/path0/node_modules/.pnpm/libpq@1.8.12/node_modules/.bin:/vercel/path0/node_modules/.bin:/pnpm7/node_modules/pnpm/dist/node-gyp-bin:/vercel/path0/node_modules/.pnpm/node_modules/.bin:/vercel/path0/node_modules/.bin:/pnpm7/node_modules/.bin:/vercel/.yarn/bin:/vercel/.config/yarn/global/node_modules/.bin:/node18/bin:/ruby27/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin)
.../libpq@1.8.12/node_modules/libpq install: find: ‘/usr/pg*’: No such file or directory
.../libpq@1.8.12/node_modules/libpq install: gyp: Call to 'which pg_config || find /usr/bin /usr/local/bin /usr/pg* /opt -executable -name pg_config -print -quit' returned exit status 1 while in binding.gyp. while trying to load binding.gyp
.../libpq@1.8.12/node_modules/libpq install: gyp ERR! configure error 
.../libpq@1.8.12/node_modules/libpq install: gyp ERR! stack Error: `gyp` failed with exit code: 1
.../libpq@1.8.12/node_modules/libpq install: gyp ERR! stack     at ChildProcess.onCpExit (/pnpm7/node_modules/pnpm/dist/node_modules/node-gyp/lib/configure.js:325:16)
.../libpq@1.8.12/node_modules/libpq install: gyp ERR! stack     at ChildProcess.emit (node:events:513:28)
.../libpq@1.8.12/node_modules/libpq install: gyp ERR! stack     at ChildProcess._handle.onexit (node:internal/child_process:291:12)
Jjeanhdev5/12/2023
Our friend GPT4 told me that;
The error message you're seeing is happening because the libpq library is trying to find the PostgreSQL development files, which it needs to build the native bindings. The issue is that those files aren't present in the Vercel build environment.

Here are a few ways you can solve this:

Prebuild your app before deploying: If possible, you could build your app in an environment where PostgreSQL is installed (such as your local development environment) and then deploy the built files to Vercel. This way, libpq doesn't need to build the bindings during the Vercel deploy process.

Use a PostgreSQL client that doesn't require native bindings: Instead of using a package that requires the PostgreSQL development files, you might consider using a pure JavaScript implementation. An example is pg-promise or node-postgres (pg). These libraries do not require any native bindings, so you won't run into the same issue.

Mock out or avoid using packages that require PostgreSQL in your Vercel deployment: If you're only using PostgreSQL in certain parts of your app, you could consider mocking those parts out or setting your code up to avoid them when running in the Vercel environment. This would likely involve setting up some environment-specific configuration in your code.
Jjeanhdev5/12/2023
Use Docker for your deployment: If Vercel supports it, you could use a Docker container for your deployment. This would allow you to set up the environment exactly as you need it, including installing PostgreSQL.

Remember, the core issue here is that libpq is trying to build native bindings and can't find the necessary PostgreSQL development files. Any solution will need to either make those files available, avoid the need for them, or build the bindings in a different environment.

In case you are using pg-native for performance reasons and you are willing to sacrifice some of it for compatibility, you can remove it and use pg alone, which is a pure JS implementation and doesn't require compiling any native code. As long as you don't explicitly require pg-native in your code, pg will work just fine.
Jjeanhdev5/12/2023
I've seen a related question here -> https://github.com/orgs/vercel/discussions/228
Jjeanhdev5/12/2023
Ok I'm trying this now
-> https://github.com/vercel/next.js/pull/48402
It seems they're fixing it
ASAndrii Sherman5/12/2023
You can also try to use Postgres.js driver
ASAndrii Sherman5/12/2023
Instead of pg
ASAndrii Sherman5/12/2023
Should be just few lines of code to change a connection and drizzle() import
ASAndrii Sherman5/12/2023
and remove pg and pg-native deps
Jjeanhdev5/12/2023
Thank you @Andrew Sherman !
I got this step working, but I'm stuck at linting step with wrong types for drizzle-orm
This is the error;
- info Linting and checking validity of types .Failed to compile.

../../node_modules/.pnpm/drizzle-orm@0.25.4_kdjlz5zwvqpzqszfg4d2qbuxze/node_modules/drizzle-orm/db.d-266cc4bc.d.ts:515:15
Type error: Non-abstract class 'PgSelect<TTableName, TSelection, TSelectMode, TNullabilityMap>' does not implement inherited abstract member 'getSQL' from class 'PgSelectQueryBuilder<PgSelectHKT, TTableName, TSelection, TSelectMode, TNullabilityMap>'.

  513 | interface PgSelect<TTableName extends string | undefined, TSelection extends ColumnsSelection, TSelectMode extends SelectMode, TNullabilityMap extends Record<string, JoinNullability> = TTableName extends string ? Record<TTableName, 'not-null'> : {}> extends PgSelectQueryBuilder<PgSelectHKT, TTableName, TSelection, TSelectMode, TNullabilityMap>, QueryPromise<SelectResult<TSelection, TSelectMode, TNullabilityMap>[]> {
  514 | }
> 515 | declare class PgSelect<TTableName extends string | undefined, TSelection, TSelectMode extends SelectMode, TNullabilityMap extends Record<string, JoinNullability> = TTableName extends string ? Record<TTableName, 'not-null'> : {}> extends PgSelectQueryBuilder<PgSelectHKT, TTableName, TSelection, TSelectMode, TNullabilityMap> {
      |               ^
  516 |     private _prepare;
  517 |     /**
  518 |      * Create a prepared statement for this query. This allows
 ELIFECYCLE  Command failed with exit code 1.
ASAndrii Sherman5/12/2023
did you enable skipLibCheck in tsConfig?
Jjeanhdev5/14/2023
That was the missing link @Andrew Sherman thank you !
You're the best man I made it work finally
Next.js + serverless Lambdas + drizzle-orm in a Turborepo
Eeko4505/24/2023
@jeanhdev Can I ask if and how exactly you got this issue resolved? I couldn't get it to work
Eeko4505/25/2023
Hey Andrew, Could you maybe help me out here?
Jjeanhdev5/26/2023
Hey @Eko sure
Jjeanhdev5/26/2023
So I finally used the postgres driver for Node instead of pg. Then I had to ‘skipLibCheck’ and it worked like a charm.
Eeko4505/27/2023
Thanks got it working 🙂
Eeko4505/27/2023
I did not have to do the skipLibCheck tho
Pphonggt6/7/2023
@jeanhdev hey can i ask how you're running migrations? I'm trying to run it in the new new instrumentation.ts file and i'm running into an issue where next.js can't find the db folder