npm becomes PID 1 with your app as a child, and it may not forward SIGTERM, so graceful shutdown can break
npm adds an extra process between Docker and your app. Depending on the version, npm may not pass signals on reliably. So your SIGTERM handler may never run, and graceful shutdown breaks. Running node directly avoids this.
The other reasons are wrong. npm does not set NODE_ENV=development on its own, and "npm start always runs the app with dev dependencies" is not true either. npm also can run in exec form.