When i run firebase deploy --only functions
, it responds with an error about node version incompatibility. My system has node 20.11.0 and firebase 13.1.0 installed (managed with asdf
).
In package.json, "engines": { "node": ">=18.5" }
is specified, and "runtime": "nodejs20"
is specified in firebase.json.
There is a dependency on sharp which requires node ^18.17.0 || ^20.3.0 || >=21.0.0
.
firebase deploy --only functions
gets past lint and other steps, but finally fails, complaining about finding node 18.5.0
(which isn’t on my system at all) and requiring at least 18.7.0
due to sharp.
I'd like the whole thing to run using node 20.3.0, but can't figure out how to make that happen.
Here’s the actual output:
✔ functions: Finished running predeploy script.
i functions: preparing codebase typescript for deployment
i functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i functions: ensuring required API cloudbuild.googleapis.com is enabled...
i artifactregistry: ensuring required API artifactregistry.googleapis.com is enabled...
✔ artifactregistry: required API artifactregistry.googleapis.com is enabled
✔ functions: required API cloudfunctions.googleapis.com is enabled
✔ functions: required API cloudbuild.googleapis.com is enabled
i functions: Loading and analyzing source code for codebase typescript to determine what to deploy
Serving at port 8928
Error: Could not load the "sharp" module using the darwin-x64 runtime
Possible solutions:
- Please upgrade Node.js:
Found 18.5.0
Requires ^18.17.0 || ^20.3.0 || >=21.0.0
- Consult the installation documentation:
See https://sharp.pixelplumbing.com/install
at Object.<anonymous> (/Users/troy/Projects/field-tracker-admin-console/functions/node_modules/sharp/lib/sharp.js:114:9)
at Module._compile (node:internal/modules/cjs/loader:1112:14)
at Module._compile (pkg/prelude/bootstrap.js:1890:32)
at Module._extensions..js (node:internal/modules/cjs/loader:1166:10)
at Module.load (node:internal/modules/cjs/loader:988:32)
at Module._load (node:internal/modules/cjs/loader:834:12)
at Module.require (node:internal/modules/cjs/loader:1012:19)
at Module.require (pkg/prelude/bootstrap.js:1851:31)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (/Users/troy/Projects/field-tracker-admin-console/functions/node_modules/sharp/lib/constructor.js:10:1)
Error: Functions codebase could not be analyzed successfully. It may have a syntax or runtime error
I took a deep dive into nodejs, npm, and a side trip through yarn to figure this out.
The fundamental issue was that I needed a specific node version and using the globally installed firebase would not support that. I learned that firebase-tools has a specific nodejs version built in so that it can be standalone and not a pain for most cases. But in my case, I needed a slightly newer node version than was in the latest firebase-tools. It seems firebase-tools version 13.1.0 has node 18.5.0 built in, but I needed at least 18.7.0 for my dependencies. I ended up using nodejs 20.11.0.
It seemed like "runtime": "nodejs20"
in firebase.json
would do the trick, but it did not. I don't know enough about the situation to say it's a bug in firebase-tools, nodejs, or npm or if I'm just missing something.
Anyhow, here's how I resolved it:
With firebase-tools installed globally, the firebase
command uses its packaged node version when deploying functions.
To use a specific version of node, install firebase-tools
via npm
and then execute it from the local (non packaged) nodejs.
Step by step:
Optionally install asdf
to manage the versions of nodejs and other tools used in various projects
Install the needed version of nodejs
- here's how with asdf:
cd <project root>
asdf add plugin nodejs
asdf install nodejs 20.11.0
asdf local nodejs 20.11.0
In the project's functions directory, use asdf again to use the same version of node
asdf local nodejs 20.11.0
In the project's root, use npm
to install firebase-tools
npm install firebase-tools
Update firebase.json
and functions/package.json
to reference the node version
firebase.json
"functions": [
{
"runtime":"nodejs20",
<- snip ->
}]
functions/package.json
"engine":{"node":">=20"},
In the project's root, add some convenience scripts to package.json
to have it launch the local firebase in the local nodejs version:
package.json
"scripts": {
"firebase": "firebase",
"df": "firebase deploy --only functions",
< add more here as needed >
}
Those "scripts" have node_modules/.bin
in their path, so, for example, the firebase
script runs node_modules/.bin/firebase
in the local nodejs.
I added the df
script because I kept forgetting to add the double dashes to make --only functions work. Without those extra double dashes, the switch applies to npm in stead of firebase.
Here's how to run those scripts in the project root:
% npm run df # same as `npm run -- firebase deploy --only functions`
% npm run firebase -V # check the version
I think that's it - all the usual firebase
commands now work using npm run -- firebase ...
. Add scripts as you see fit to make it easier to type them correctly.
Thanks go to @DougStevenson for prodding me in the right direction!