Strapi refuses to boot:
debug: ⛔️ Server wasn't able to start properly.
error: Cannot destructure property 'client' of 'db.config.connection' as it is undefined.
TypeError: Cannot destructure property 'client' of 'db.config.connection' as it is undefined.
at getDialect (.../@strapi/database/dist/index.js)
at new Database (...)
at Strapi.bootstrap (...)What it means
Strapi is trying to read client ('postgres', 'mysql', 'sqlite') from your database configuration in order to pick a dialect. It got undefined for the whole connection object.
This is not a wrong password, an unreachable host, or a firewall. Strapi loaded no database configuration at all. Either config/database was not found, or it was found and produced nothing usable.
Once you frame it that way, the search space is small.
Confirm it in one step
Add a log at the very top of the config file:
console.log('>>> config/database loaded');
export default ({ env }) => ({
connection: {
client: env('DATABASE_CLIENT', 'postgres'),
connection: {
host: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 5432),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD'),
ssl: env.bool('DATABASE_SSL', false),
},
},
});If >>> config/database loaded never appears in the logs, the file is not being loaded, so go to causes 1 to 4. If it does appear and the error still fires, the file loaded but returned the wrong shape, so go to cause 5.
Cause 1: TypeScript compiled nothing (noEmit)
The most common cause on TypeScript projects, and the one that resolved the original forum thread.
Strapi builds a TypeScript project by compiling config/, src/, and friends into dist/. If your tsconfig.json contains:
{
"compilerOptions": {
"noEmit": true
}
}…then tsc type-checks and writes no output. The build appears to succeed. dist/ has no config/database.js. Strapi starts, finds nothing, and throws.
{
"extends": "@strapi/typescript-utils/tsconfigs/server",
"compilerOptions": {
"outDir": "dist",
"rootDir": "."
// no "noEmit"
},
"include": ["./", "src/**/*.json"],
"exclude": ["node_modules/", "build/", "dist/", ".cache/", ".tmp/", "src/admin/", "**/*.test.ts", "src/plugins/**"]
}noEmit: true usually arrives by copying a frontend tsconfig.json, or by a well-meaning editor suggestion. Remove it and rebuild.
Verify:
npm run build
ls -la dist/config/
# database.js must be thereCause 2: The file is not in the container
The Docker version of the same problem. Your Dockerfile copies the wrong path, so config/ never makes it into the image:
# Build context is the repo root, but the app lives in ./backend
COPY . . # ← copies the repo root, not the appCOPY ./backend . # ← correct for that layoutCheck inside the running container rather than guessing:
docker compose exec strapi ls -la /opt/app/config/
docker compose exec strapi ls -la /opt/app/dist/config/Also check .dockerignore. A broad pattern can exclude config/ or tsconfig.json without anyone noticing:
node_modules
.git
.env
# make sure nothing here matches config/ or tsconfig.jsontsconfig.json must be in the image if you build inside it. Without it, tsc falls back to defaults, output lands in unexpected places, and you get this error.
Cause 3: An environment-specific config that returns nothing
config/env/<NODE_ENV>/database.ts completely replaces the base config/database.ts when that NODE_ENV is active; it is not merged.
So a production override that is empty, malformed, or returns a different shape leaves you with no database config in production while development works perfectly.
ls -la config/env/*/
cat config/env/production/database.* 2>/dev/nullIf the file exists, make sure it returns the full object, not a partial one:
export default ({ env }) => ({
connection: {
client: 'postgres',
connection: {
connectionString: env('DATABASE_URL'),
ssl: { rejectUnauthorized: false },
},
debug: false,
},
});Note that this file is only loaded when NODE_ENV=production. If your platform sets NODE_ENV=prod or leaves it unset, the folder is ignored and you fall back to the base config, which may itself be fine, or may be the SQLite default.
Cause 4: Running from the wrong directory, or the wrong entry point
Strapi resolves config/ relative to the application root. Starting the process from elsewhere, or pointing a process manager at the wrong cwd, breaks that resolution.
module.exports = {
apps: [{
name: 'strapi',
cwd: '/var/www/strapi', // must be the project root
script: 'npm',
args: 'run start',
}],
};For TypeScript projects started programmatically, the factory needs distDir:
const strapi = require('@strapi/strapi');
strapi.createStrapi({ distDir: './dist' }).start();Without distDir, the process looks for configuration in the source tree at runtime, finds .ts files it cannot execute, and loads nothing. This is a frequent cPanel and shared-hosting failure, because those environments start Node through a wrapper whose working directory is not what you expect.
Cause 5: The config file returns the wrong shape
Less common, but it happens after refactors. Strapi expects the exported function to return an object with a connection key:
// Correct
export default ({ env }) => ({
connection: {
client: 'postgres',
connection: { /* host, port, ... */ },
},
});
// Wrong: missing the outer `connection` wrapper
export default ({ env }) => ({
client: 'postgres',
connection: { /* ... */ },
});
// Wrong: exports the object instead of a function returning it
export default {
connection: { client: 'postgres', connection: {} },
};Note the deliberate double nesting: connection.connection. The outer one is Knex's configuration; the inner one is the connection parameters. It reads oddly and it is correct.
Also watch for a stray module.exports in a .ts file, or export default in a .js file where the project expects CommonJS. A module system mismatch means the export is undefined and Strapi sees an empty config.
Diagnostic sequence
# 1. Does the source file exist and is it valid?
ls -la config/database.*
npx tsc --noEmit -p tsconfig.json # type errors only, no output
# 2. Did the build emit it?
npm run build
ls -la dist/config/
# 3. In a container, is it actually there?
docker compose exec strapi ls -la /opt/app/dist/config/
# 4. Which NODE_ENV is active, and is there an override?
docker compose exec strapi printenv NODE_ENV
ls -la config/env/
# 5. Is the process running from the right directory?
pm2 describe strapi | grep -i "exec cwd"Related errors
| Error | Meaning |
|---|---|
Cannot destructure property 'client' | Config file did not load at all |
SASL: ... client password must be a string | Config loaded, password is undefined |
password authentication failed | Config loaded, credentials are wrong |
ECONNREFUSED | Config loaded, nothing listening at that address |
Knex: Timeout acquiring a connection | Config loaded, packets are being dropped |
Working out which of these you have narrows the problem enormously: the first is a build or packaging issue, the rest are runtime and network issues.


![Fixing TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string in Strapi](https://automatic-life-0194aa0342.media.strapiapp.com/strapi_err_invalid_arg_type_path_must_be_string_ea76191703.png)
