Netlify function with knex mysql2 driver not working in Netlify

Hi. I’m experiencing an issue with my deployed function.

Mi netlify site URL is: https://inquisitive-truffle-a50a86.netlify.app.
I have an endpoint POST https://inquisitive-truffle-a50a86.netlify.app/.netlify/functions/invoices who is returning this error

Knex: run
$ npm install mysql2 --save
Cannot find module 'mysql2'
Require stack:
- /var/task/node_modules/knex/lib/dialects/mysql2/index.js",
- /var/task/node_modules/knex/lib/dialects/index.js",
- /var/task/node_modules/knex/lib/knex-builder/internal/config-resolver.js",
- /var/task/node_modules/knex/lib/knex-builder/Knex.js",
- /var/task/node_modules/knex/lib/index.js",
- /var/task/node_modules/knex/knex.js",
- /var/task/src/db/mysql.js",
- /var/task/src/repositories/customers.js",
- /var/task/src/services/generateInvoice.js",
- /var/task/src/handlers/invoices/post.js",
- /var/task/src/handlers/invoices/index.js",
- /var/task/netlify/functions/invoices.js/index.js",
- /var/task/invoices.js",
- /var/runtime/index.mjs
    at Client_MySQL2.initializeDriver (/var/task/node_modules/knex/lib/client.js:194:13)
    at new Client (/var/task/node_modules/knex/lib/client.js:75:12)
    at new Client_MySQL (/var/task/node_modules/knex/lib/dialects/mysql/index.js:21:1)
    at new Client_MySQL2 (/var/task/node_modules/knex/lib/dialects/mysql2/index.js:9:1)
    at knex (/var/task/node_modules/knex/lib/knex-builder/Knex.js:16:28)
    at Object.<anonymous> (/var/task/src/db/mysql.js:16:12)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)"]}

I am using NodeJS v16.17.1 and npm 8.15.0. In my local env, I run

npm i

to install dependencies and use netlify CLI to run locally. On my Netlify settings I set the same command to run on the correct folder but when I run a request, the error says it is not finding the mysql2 module. It looks like even it is finding knex module, the mysql2 is not found.

I thought it was not installing node_modules but it is installing them indeed. You can check the deploy logs:

11:12:17 AM: Build ready to start
11:12:18 AM: build-image version: d7b3dbfb0846505993c9a131894d1858074c90b4 (focal)
11:12:18 AM: build-image tag: v4.10.1
11:12:18 AM: buildbot version: 1c362ef848ac5e35535bdb572ebca893db28c8a0
11:12:18 AM: Building without cache
11:12:18 AM: Starting to prepare the repo for build
11:12:18 AM: No cached dependencies found. Cloning fresh repo
11:12:18 AM: git clone https://github.com/kpedrozag/despacho-siteapp
11:12:19 AM: Preparing Git Reference refs/heads/main
11:12:19 AM: Parsing package.json dependencies
11:12:20 AM: Different publish path detected, going to use the one specified in the Netlify configuration file: 'server' versus '' in the Netlify UI
11:12:20 AM: Different functions path detected, going to use the one specified in the Netlify configuration file: 'server/netlify/functions' versus 'netlify/functions' in the Netlify UI
11:12:20 AM: Starting build script
11:12:20 AM: Installing dependencies
11:12:20 AM: Python version set to 2.7
11:12:20 AM: Downloading and installing node v16.17.1...
11:12:21 AM: Downloading https://nodejs.org/dist/v16.17.1/node-v16.17.1-linux-x64.tar.xz...
11:12:21 AM: Computing checksum with sha256sum
11:12:21 AM: Checksums matched!
11:12:23 AM: Now using node v16.17.1 (npm v8.15.0)
11:12:23 AM: Started restoring cached build plugins
11:12:23 AM: Finished restoring cached build plugins
11:12:23 AM: Attempting ruby version 2.7.2, read from environment
11:12:24 AM: Using ruby version 2.7.2
11:12:24 AM: Using PHP version 8.0
11:12:24 AM: No npm workspaces detected
11:12:24 AM: Started restoring cached node modules
11:12:24 AM: Finished restoring cached node modules
11:12:24 AM: Installing NPM modules using NPM version 8.15.0
11:12:25 AM: npm WARN config tmp This setting is no longer used.  npm stores temporary files in a special
11:12:25 AM: npm WARN config location in the cache, and they are managed by
11:12:25 AM: npm WARN config     [`cacache`](http://npm.im/cacache).
11:12:25 AM: npm WARN config tmp This setting is no longer used.  npm stores temporary files in a special
11:12:25 AM: npm WARN config location in the cache, and they are managed by
11:12:25 AM: npm WARN config     [`cacache`](http://npm.im/cacache).
11:12:25 AM: added 58 packages, and audited 59 packages in 767ms
11:12:25 AM: 6 packages are looking for funding
11:12:25 AM:   run `npm fund` for details
11:12:25 AM: found 0 vulnerabilities
11:12:25 AM: NPM modules installed
11:12:26 AM: npm WARN config tmp This setting is no longer used.  npm stores temporary files in a special
11:12:26 AM: npm WARN config location in the cache, and they are managed by
11:12:26 AM: npm WARN config     [`cacache`](http://npm.im/cacache).
11:12:26 AM: Started restoring cached go cache
11:12:26 AM: Finished restoring cached go cache
11:12:26 AM: Installing Go version 1.17 (requested 1.17)
11:12:30 AM: unset GOOS;
11:12:30 AM: unset GOARCH;
11:12:30 AM: export GOROOT='/opt/buildhome/.gimme/versions/go1.17.linux.amd64';
11:12:30 AM: export PATH="/opt/buildhome/.gimme/versions/go1.17.linux.amd64/bin:${PATH}";
11:12:30 AM: go version >&2;
11:12:30 AM: export GIMME_ENV="/opt/buildhome/.gimme/env/go1.17.linux.amd64.env"
11:12:30 AM: go version go1.17 linux/amd64
11:12:30 AM: Installing missing commands
11:12:30 AM: Verify run directory
11:12:31 AM: ​
11:12:31 AM: ────────────────────────────────────────────────────────────────
11:12:31 AM:   Netlify Build                                                 
11:12:31 AM: ────────────────────────────────────────────────────────────────
11:12:31 AM: ​
11:12:31 AM: ❯ Version
11:12:31 AM:   @netlify/build 27.18.4
11:12:31 AM: ​
11:12:31 AM: ❯ Flags
11:12:31 AM:   baseRelDir: true
11:12:31 AM:   buildId: 63307de0815f09235da9f851
11:12:31 AM:   deployId: 63307de0815f09235da9f853
11:12:31 AM: ​
11:12:31 AM: ❯ Current directory
11:12:31 AM:   /opt/build/repo/server
11:12:31 AM: ​
11:12:31 AM: ❯ Config file
11:12:31 AM:   No config file was defined: using default values.
11:12:31 AM: ​
11:12:31 AM: ❯ Context
11:12:31 AM:   production
11:12:31 AM: ​
11:12:31 AM: ────────────────────────────────────────────────────────────────
11:12:31 AM:   1. Build command from Netlify app                             
11:12:31 AM: ────────────────────────────────────────────────────────────────
11:12:31 AM: ​
11:12:31 AM: $ pwd && npm i && ls
11:12:31 AM: /opt/build/repo/server
11:12:31 AM: npm WARN config tmp This setting is no longer used.  npm stores temporary files in a special
11:12:31 AM: npm WARN config location in the cache, and they are managed by
11:12:31 AM: npm WARN config     [`cacache`](http://npm.im/cacache).
11:12:31 AM: up to date, audited 59 packages in 295ms
11:12:31 AM: 6 packages are looking for funding
11:12:31 AM:   run `npm fund` for details
11:12:31 AM: found 0 vulnerabilities
11:12:31 AM: netlify
11:12:31 AM: node_modules
11:12:31 AM: package.json
11:12:31 AM: package-lock.json
11:12:31 AM: README.md
11:12:31 AM: scripts
11:12:31 AM: src
11:12:31 AM: ​
11:12:31 AM: (build.command completed in 507ms)
11:12:31 AM: ​
11:12:31 AM: ────────────────────────────────────────────────────────────────
11:12:31 AM:   2. Functions bundling                                         
11:12:31 AM: ────────────────────────────────────────────────────────────────
11:12:31 AM: ​
11:12:31 AM: Packaging Functions from netlify/functions directory:
11:12:31 AM:  - invoices.js/index.js
11:12:31 AM: ​
11:12:32 AM: ​
11:12:32 AM: (Functions bundling completed in 898ms)
11:12:32 AM: ​
11:12:32 AM: ────────────────────────────────────────────────────────────────
11:12:32 AM:   3. Deploy site                                                
11:12:32 AM: ────────────────────────────────────────────────────────────────
11:12:32 AM: ​
11:12:32 AM: Starting to deploy site from 'server'
11:12:32 AM: Creating deploy tree 
11:12:32 AM: Creating deploy upload records
11:12:33 AM: 0 new files to upload
11:12:33 AM: 1 new functions to upload
11:12:38 AM: Site deploy was successfully initiated
11:12:38 AM: ​
11:12:38 AM: (Deploy site completed in 6.1s)
11:12:39 AM: ​
11:12:39 AM: ────────────────────────────────────────────────────────────────
11:12:39 AM:   Netlify Build Complete                                        
11:12:39 AM: ────────────────────────────────────────────────────────────────
11:12:39 AM: ​
11:12:39 AM: (Netlify Build completed in 7.5s)
11:12:39 AM: Starting post processing
11:12:39 AM: Post processing - HTML
11:12:39 AM: Post processing - header rules
11:12:39 AM: Caching artifacts
11:12:39 AM: Started saving node modules
11:12:39 AM: Finished saving node modules
11:12:39 AM: Started saving build plugins
11:12:39 AM: Finished saving build plugins
11:12:39 AM: Started saving pip cache
11:12:39 AM: Finished saving pip cache
11:12:39 AM: Started saving emacs cask dependencies
11:12:39 AM: Finished saving emacs cask dependencies
11:12:39 AM: Started saving maven dependencies
11:12:39 AM: Finished saving maven dependencies
11:12:39 AM: Started saving boot dependencies
11:12:39 AM: Finished saving boot dependencies
11:12:39 AM: Started saving rust rustup cache
11:12:39 AM: Finished saving rust rustup cache
11:12:39 AM: Started saving go dependencies
11:12:39 AM: Finished saving go dependencies
11:12:39 AM: Post processing - redirect rules
11:12:39 AM: Post processing done
11:12:40 AM: Build script success
11:12:40 AM: Uploading Cache of size 98.2MB
11:12:41 AM: Finished processing build request in 22.969357829s
11:12:42 AM: Site is live ✨

Found a similar issue: Can I use Netlify Functions along with KnexJS?.

I ame replicating to evaluate if this works.

It worked!

this my before vs after programming block to instance the connection to MySQL using Knex:

Before

const knex = require('knex');
const { MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE } = process.env;
const MySQLConfig = {
  client: 'mysql2',
  connection: {
    host: MYSQL_HOST,
    port: MYSQL_PORT,
    user: MYSQL_USER,
    password: MYSQL_PASSWORD,
    database: MYSQL_DATABASE,
  },
};
const db = knex(MySQLConfig);
module.exports = db;

After

const knex = require('knex');
const knexServerlessMySQL = require('knex-serverless-mysql');
const serverlessMySQL = require('serverless-mysql');
const { MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE } = process.env;
const mysql = serverlessMySQL({
  config: {
    host: MYSQL_HOST,
    port: MYSQL_PORT,
    user: MYSQL_USER,
    password: MYSQL_PASSWORD,
    database: MYSQL_DATABASE,
  },
});
const knexMySQLConfig = {
  client: knexServerlessMySQL,
  mysql,
};
const db = knex(knexMySQLConfig);
module.exports = db;