Skip to content

perf: share db, docker and auth singletons across duplicated bundles#4777

Merged
Siumauricio merged 1 commit into
canaryfrom
perf/dedupe-module-singletons
Jul 9, 2026
Merged

perf: share db, docker and auth singletons across duplicated bundles#4777
Siumauricio merged 1 commit into
canaryfrom
perf/dedupe-module-singletons

Conversation

@Siumauricio

Copy link
Copy Markdown
Contributor

Problem

@dokploy/server gets bundled several times into the same server process: an inline copy in dist/server.mjs (esbuild + tsconfig paths for subpath imports), the compiled node_modules copy (bare imports left external by packages: "external"), and 4 copies duplicated across .next/server/chunks by transpilePackages. Every module-level side effect runs once per copy:

  • Up to 6 postgres.js pools per process — db/index.ts explicitly skipped the globalThis cache in production (measured: 21 idle connections on a fresh instance after ~20 min of traffic)
  • 6 dockerode clients, and the repeated Using Docker socket log at boot (7 times)
  • 6 independent better-auth instances

On top of that, the image keeps pnpm resident as a process wrapper (~100MB RSS doing nothing). Measured container usage: ~930MB after 27 minutes up (801MB node + 99MB pnpm).

Changes

  • db/index.ts: use the globalThis cache in production too → one pool per process
  • constants/index.ts: cache the dockerode client on globalThis → also fixes the repeated socket logs
  • lib/auth.ts: wrap betterAuth() in a createBetterAuth() factory and cache the instance on globalThis
  • Dockerfile: exec node directly in CMD instead of going through pnpm start

Note: the auth.ts diff is almost entirely indentation from the factory wrap — review with whitespace hidden (git diff -w / hide whitespace on GitHub, real diff is +16/−2).

Code copies are still duplicated across bundles (drizzle schema instantiated per copy); deduplicating the bundling itself (serverExternalPackages in prod + wildcard exports to dist/) is a follow-up.

The @dokploy/server modules get bundled multiple times per process
(esbuild inline copy, compiled node_modules copy, and several Next.js
chunks via transpilePackages), so every module-level side effect ran
once per copy: up to 6 postgres pools, 6 dockerode clients and 6
better-auth instances in the server process, plus the repeated
'Using Docker socket' logs at boot.

- db/index.ts: use the globalThis cache in production too (one pool per process)
- constants/index.ts: cache the dockerode client on globalThis
- lib/auth.ts: wrap betterAuth() in a factory and cache the instance
- Dockerfile: exec node directly instead of leaving pnpm resident (~100MB RSS)
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. enhancement New feature or request labels Jul 9, 2026
@Siumauricio Siumauricio merged commit 856cf33 into canary Jul 9, 2026
4 checks passed
@Siumauricio Siumauricio deleted the perf/dedupe-module-singletons branch July 9, 2026 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant