From d4b597e14e4b80fc6f8636b610b3913b85d9d31a Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Tue, 16 Jun 2026 11:16:09 +0200 Subject: [PATCH] fix(docker): run twenty-server in production mode (NODE_ENV=production) (#21635) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What Set `ENV NODE_ENV=production` in the `twenty-server` Docker stage (inherited by `twenty-server-aws` and `twenty`). ## Why — root cause of the empty verification emails Verification emails have been delivered with an **empty body** in deployed environments — the subject renders ("Bienvenue chez Twenty : Veuillez confirmer votre email") but the HTML is ``, an **errored React Suspense boundary**. Prod logs showed: ``` TypeError: dispatcher.getOwner is not a function ``` Chain: 1. The prod server stages never set `NODE_ENV`, so at runtime it's **unset** → React loads its **development** builds. 2. Since the **React 18→19 upgrade** (#21531), React 19's dev JSX runtime calls `dispatcher.getOwner()` (React 18's did not — which is why this is a recent regression). 3. That call throws in the server runtime → the email React tree throws during SSR → `@react-email/render` (which streams without an `onError`) swallows it into an errored `` boundary → the body ships empty. The subject is unaffected because it's built without React. Production React never tracks owner, so `jsx()` never calls `getOwner` — setting `NODE_ENV=production` removes the failing code path entirely. It's also simply the correct prod configuration (dev React builds are slower and emit dev-only behavior). ## Scope / safety - Only the prod runtime stages are affected. The dev image (`twenty-app-dev`) keeps its own `NODE_ENV=development`. - Verified the deployed image currently bakes `NODE_ENV=[]` (unset) and has a single, matched `react`/`react-dom` 19.2.7 — so this is a mode issue, not a duplicate-React issue. ## Related - Mitigation already in place: twentyhq/twenty-infra#729 disables email verification on prod-eu meanwhile (revert once this ships). - Diagnostic logging: #21628 (can be reverted after this lands). Review in cubic --- packages/twenty-docker/twenty/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/twenty-docker/twenty/Dockerfile b/packages/twenty-docker/twenty/Dockerfile index 366b4a520f..98f137d66f 100644 --- a/packages/twenty-docker/twenty/Dockerfile +++ b/packages/twenty-docker/twenty/Dockerfile @@ -105,6 +105,7 @@ WORKDIR /app/packages/twenty-server ARG APP_VERSION ENV APP_VERSION=$APP_VERSION +ENV NODE_ENV=production # Workspace root config COPY --chown=1000 --from=twenty-server-build /app/package.json /app/yarn.lock /app/.yarnrc.yml /app/