✨ Strapi MCP is now Generally Available - let your agents manage your Strapi content ✨

EcosystemIntermediate●6 min read

"Cannot destructure property 'client' of 'db.config.connection'" in Strapi

●September 9, 2026
"Cannot destructure property 'client' of 'db.config.connection'" in Strapi

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 there

Cause 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 app
COPY ./backend .    # ← correct for that layout

Check 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.json

tsconfig.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/null

If 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"
ErrorMeaning
Cannot destructure property 'client'Config file did not load at all
SASL: ... client password must be a stringConfig loaded, password is undefined
password authentication failedConfig loaded, credentials are wrong
ECONNREFUSEDConfig loaded, nothing listening at that address
Knex: Timeout acquiring a connectionConfig 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.

Further reading

Theodore Kelechukwu OnyejiakuDevRel and Community | Software Developer | Technical Writer

Theodore is a Technical Writer and a full-stack software developer. He loves writing technical articles, building solutions, and sharing his expertise.

The True TCO of Self-Hosting a Headless CMS
Ecosystem·12 min read

The True TCO of Self-Hosting a Headless CMS

Discover the real cost of self-hosting Strapi 5: infrastructure, DevOps labor, security, migrations, and hidden costs—with a practical TCO checklist.

·September 24, 2026
How Do You Preserve SEO Rankings During a CMS Migration?
Ecosystem·13 min read

How Do You Preserve SEO Rankings During a CMS Migration?

A developer's CMS migration SEO checklist: URL mapping, 301 redirects, on-page parity, robots.txt, redirect testing, and post-launch monitoring.

·September 24, 2026
What Is a Content Agent? Agentic AI for CMS Workflows Explained
Ecosystem·24 min read

What Is a Content Agent? Agentic AI for CMS Workflows Explained

Learn what a content agent is, how the observe-plan-act-evaluate loop works, and when agentic AI makes sense for your CMS workflows and content operations.

·September 24, 2026