Skip to content

fix: avoid module-scoped DB clients in workers#964

Open
Sigmabrogz wants to merge 2 commits intoAmanVarshney01:mainfrom
Sigmabrogz:fix/issue-935
Open

fix: avoid module-scoped DB clients in workers#964
Sigmabrogz wants to merge 2 commits intoAmanVarshney01:mainfrom
Sigmabrogz:fix/issue-935

Conversation

@Sigmabrogz
Copy link
Copy Markdown

@Sigmabrogz Sigmabrogz commented Mar 12, 2026

Addresses #935. This draft PR starts changing DB clients to be instantiated per request (via createDb) in Cloudflare Workers templates to avoid stale TCP connections. Needs further updates in TRPC/Hono contexts.

Summary by CodeRabbit

  • Refactor
    • Updated SQLite database template initialization to use a factory function pattern instead of pre-configured instance export, enabling more flexible runtime configuration.

Signed-off-by: Sigma <bot@example.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 12, 2026

@rhoggs-bot-test-account is attempting to deploy a commit to the Better T Stack Team on Vercel.

A member of the Team first needs to authorize it.

@Sigmabrogz
Copy link
Copy Markdown
Author

Hi, the PR is ready for review. Thanks!

@AmanVarshney01 AmanVarshney01 marked this pull request as ready for review March 24, 2026 17:01
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

Walkthrough

Modified SQLite Drizzle template to export a factory function createDb instead of a static db constant across Bun/Node/None, Workers/D1, and Workers/LibSQL runtime configurations. The factory accepts an optional environment parameter and returns a drizzle instance.

Changes

Cohort / File(s) Summary
SQLite Drizzle Template
packages/template-generator/templates/db/drizzle/sqlite/src/index.ts.hbs
Replaced static db export with createDb factory function across all runtime branches. Each branch now returns a new drizzle instance when invoked, accepting an optional env parameter for environment-specific configurations.

Possibly related issues

  • AmanVarshney01/create-better-t-stack#935: This PR addresses the issue's recommendation by shifting from module-scoped DB clients to factory-based request-scoped instances, improving database connection handling in Workers environments.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: converting module-scoped DB clients to factory functions, which directly addresses the issue of avoiding stale connections in workers environments.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 66adbe197c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

});

export const db = drizzle({ client, schema });
export const createDb = (env?: any) => drizzle({ client, schema });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep db export available for generated consumers

This change renames the package-level export from db to createDb, but the rest of the templates still import db directly (for example auth/better-auth/server/base/src/index.ts.hbs lines 81 and 153, and examples/todo/server/drizzle/base/src/routers/todo.ts.hbs lines 4 and 45). Any generated drizzle+sqlite project that includes those flows will fail type-check/build with “no exported member db” until every consumer is migrated in the same change.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/template-generator/templates/db/drizzle/sqlite/src/index.ts.hbs (1)

30-37: ⚠️ Potential issue | 🟠 Major

Workers/LibSQL branch does not fix the stale TCP connection issue.

The PR objective is to avoid module-scoped clients causing stale TCP connections in Workers. However, in this branch, client is still created at module scope (lines 30-35). The createDb function merely wraps this same module-scoped client, so the underlying TCP connection is still shared across requests.

To properly fix this, the createClient call should move inside createDb:

🛠️ Proposed fix: Instantiate client per request
 import { drizzle } from "drizzle-orm/libsql";
 import { env } from "@{{projectName}}/env/server";
 import { createClient } from "@libsql/client";

-const client = createClient({
-	url: env.DATABASE_URL || "",
-{{`#if` (eq dbSetup "turso")}}
-	authToken: env.DATABASE_AUTH_TOKEN,
-{{/if}}
-});
-
-export const createDb = (env?: any) => drizzle({ client, schema });
+export const createDb = () => {
+	const client = createClient({
+		url: env.DATABASE_URL || "",
+{{`#if` (eq dbSetup "turso")}}
+		authToken: env.DATABASE_AUTH_TOKEN,
+{{/if}}
+	});
+	return drizzle({ client, schema });
+};
🧹 Nitpick comments (1)
packages/template-generator/templates/db/drizzle/sqlite/src/index.ts.hbs (1)

14-14: Unused env parameter in non-D1 branches creates a confusing API.

In lines 14 and 37, createDb accepts env?: any but the parameter is never used—the function still relies on the module-scoped client (which uses the imported env). This inconsistency makes the API contract unclear.

If the parameter isn't needed for these branches, consider removing it to avoid confusion. If you want a uniform signature across all branches, document why it's optional here.

♻️ Option: Remove unused parameter for clarity
-export const createDb = (env?: any) => drizzle({ client, schema });
+export const createDb = () => drizzle({ client, schema });

Also applies to: 37-37


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea04c72e-8323-49e4-ab86-dd86e8eeac83

📥 Commits

Reviewing files that changed from the base of the PR and between 597a74e and 66adbe1.

📒 Files selected for processing (1)
  • packages/template-generator/templates/db/drizzle/sqlite/src/index.ts.hbs

});

export const db = drizzle({ client, schema });
export const createDb = (env?: any) => drizzle({ client, schema });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Breaking change: Renaming db to createDb breaks downstream imports.

The context snippets show that other templates (todo.ts.hbs, better-auth/server/base/src/index.ts.hbs) import db as a named import:

import { db } from "@{{projectName}}/db";

These imports will fail after this change. Either update all consuming templates to use createDb, or re-export a compatibility alias.

🔧 Option: Add backward-compatible re-export (all three branches)
-export const createDb = (env?: any) => drizzle({ client, schema });
+export const createDb = (env?: any) => drizzle({ client, schema });
+export const db = createDb();

Or update all downstream templates to call createDb() where db was used.

#!/bin/bash
# Find all templates that import `db` from the db package
rg -n "import.*\bdb\b.*from.*@.*db" packages/template-generator/templates --glob '*.hbs'

Also applies to: 24-24, 37-37

@@ -21,7 +21,7 @@ import * as schema from "./schema";
import { drizzle } from "drizzle-orm/d1";
import { env } from "@{{projectName}}/env/server";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Unused import: env is imported but shadowed by function parameter.

Line 22 imports env from the env package, but line 24 declares a function parameter also named env. The imported env is never used in the D1 branch.

🧹 Proposed fix: Remove unused import
 {{`#if` (eq dbSetup "d1")}}
 import { drizzle } from "drizzle-orm/d1";
-import { env } from "@{{projectName}}/env/server";

 export const createDb = (env: any) => drizzle(env.DB, { schema });

Also applies to: 24-24

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants