Skip to content

Conversation

@0ski
Copy link
Collaborator

@0ski 0ski commented Dec 2, 2025

Vercel's NeonDB integration renders database connection environment variables at runtime, which means Trigger.dev cannot directly sync these values during the build process. This change adds support for fetching branch-specific NeonDB connection strings via the Neon API.

feat(build): Add syncNeonEnvVars extension and improve Vercel env var syncing

Add a new syncNeonEnvVars build extension for syncing environment variables
from Neon database projects to Trigger.dev. The extension automatically detects
branches and builds appropriate PostgreSQL connection strings for non-production
environments (staging, dev, preview).

Features of syncNeonEnvVars:

  • Fetches branch-specific database credentials from Neon API
  • Generates all standard Postgres connection strings (DATABASE_URL, POSTGRES_URL,
    POSTGRES_PRISMA_URL, etc.) with both pooled and unpooled variants
  • Supports custom database name, role name, and env var prefix options
  • Skips automatically in Vercel environments (Neon's Vercel integration handles this)
  • Skips for production environments (designed for preview/staging/dev branches)

Improvements to syncVercelEnvVars:

  • When running in a Vercel build environment (detected via VERCEL env var),
    values are now read from process.env instead of the Vercel API response
  • This ensures the build uses the actual runtime values Vercel provides
  • Removed embedded Neon-specific logic (now handled by separate extension)
  • Simplified and cleaned up the extension code

Documentation updates for both extensions with usage examples and configuration
options.

Closes #2714

✅ Checklist

  • I have followed every step in the contributing guide
  • The PR title follows the convention.
  • I ran and tested the code works

Testing

Set up Vercel + Trigger.dev envs, used Vercel's chat-bot-ai template.

…ents

Vercel's NeonDB integration renders database connection environment
variables at runtime, which means Trigger.dev cannot directly sync
these values during the build process. This change adds support for
fetching branch-specific NeonDB connection strings via the Neon API.

Changes:
- Discover NEON_PROJECT_ID from incoming Vercel environment variables
- Call NeonDB API to search for branches matching the git branch name
- Filter branches to find exact matches with Vercel environment prefix
  (e.g., "preview/branch-name") to avoid false positives from partial
  string matches
- Retrieve branch endpoints and select the write endpoint (or first
  available)
- Build connection strings (DATABASE_URL, POSTGRES_URL, etc.) using
  the branch endpoint host while preserving user/password credentials

Safety measures for non-production environments:
- Filter out all Neon-related env vars (DATABASE_URL, PGHOST, etc.)
  before calling the Neon API to prevent accidental use of production
  database credentials
- Only add branch-specific database env vars if a matching Neon branch
  is found and the API call succeeds
- If neonDbAccessToken is not provided or the API fails, non-production
  environments will not receive any database connection env vars

Usage:
Users must provide a NEON_ACCESS_TOKEN (via options or env var) to
enable automatic branch resolution for preview deployments. Production
environments continue to use Vercel's standard env var sync without
modification.
@changeset-bot
Copy link

changeset-bot bot commented Dec 2, 2025

🦋 Changeset detected

Latest commit: 702f3b4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 26 packages
Name Type
@trigger.dev/build Patch
trigger.dev Patch
@trigger.dev/python Patch
d3-chat Patch
references-d3-openai-agents Patch
references-nextjs-realtime Patch
references-realtime-hooks-test Patch
references-realtime-streams Patch
references-telemetry Patch
@trigger.dev/core Patch
@trigger.dev/react-hooks Patch
@trigger.dev/redis-worker Patch
@trigger.dev/rsc Patch
@trigger.dev/schema-to-json Patch
@trigger.dev/sdk Patch
@trigger.dev/database Patch
@trigger.dev/otlp-importer Patch
@internal/cache Patch
@internal/clickhouse Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/zod-worker Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

Walkthrough

Adds a new Neon environment-variable synchronization extension (syncNeonEnvVars) that queries the Neon API to derive database connection env vars (optionally prefixed) and returns them as EnvVar objects. Updates the Vercel sync logic to prefer values from process.env when running in a Vercel build while still using the Vercel API to determine which variables are configured. Re-exports the Neon sync extension from the core extensions barrel. Adds documentation and examples for both Vercel and Neon sync extensions. Public API surface now includes the new export and the new syncNeonEnvVars symbol.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring extra attention:

  • packages/build/src/extensions/core/neonSyncEnvVars.ts: Neon API flows (branch selection, endpoint/database/role discovery), input validation, and construction of returned env var values and prefixes.
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts: new Vercel-specific value-resolution logic (preferring process.env), filtering/mapping changes, and correct propagation of computed values into returned EnvVar objects.
  • packages/build/src/extensions/core.ts: new re-export; verify export surface and module resolution.
  • docs/config/extensions/syncEnvVars.mdx and docs/guides/examples/vercel-sync-env-vars.mdx: accuracy of added guidance and examples.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding NeonDB branch resolution support for Vercel preview environments, which is the primary feature introduced in this PR.
Description check ✅ Passed The description is comprehensive, covering the problem, features added, improvements made, and includes testing information. It follows the template with completed checklist items.
Linked Issues check ✅ Passed The PR fully addresses issue #2714: it modifies syncVercelEnvVars to read values from process.env instead of API responses, and adds syncNeonEnvVars to safely fetch branch-specific database credentials, preventing production DB credentials from being synced to preview environments.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue: modifications to syncVercelEnvVars, new syncNeonEnvVars extension, documentation updates, and changeset entry are all necessary to address the NeonDB Vercel integration issue.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch oo/gh-issue-2714

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.

@0ski 0ski self-assigned this Dec 2, 2025
Copy link
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: 1

🧹 Nitpick comments (1)
packages/build/src/extensions/core/vercelSyncEnvVars.ts (1)

68-72: Consider adding timeouts to external API calls.

The fetch calls to the Neon API lack timeout handling. If the Neon API is slow or unresponsive, the build could hang indefinitely.

Consider using AbortController with a timeout:

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s timeout

try {
  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${neonDbAccessToken}` },
    signal: controller.signal,
  });
  // ...
} finally {
  clearTimeout(timeoutId);
}

Also applies to: 101-105

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af9b3e1 and 49b2f68.

📒 Files selected for processing (1)
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
🧠 Learnings (1)
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (22)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
packages/build/src/extensions/core/vercelSyncEnvVars.ts (5)

14-34: LGTM!

The constants are well-organized and the list of Neon environment variables is comprehensive. The empty default prefix provides flexibility for customization.


36-45: LGTM!

Types are properly defined using the type keyword as per coding guidelines, and fields align with the Neon API response structure.


192-200: LGTM!

The new optional parameters maintain backward compatibility while enabling the Neon integration. The function signature extension is clean.


292-330: Verify intended behavior: non-production environments get no DB vars on Neon API failure.

When neonProjectId is present but the Neon API call fails (or no matching branch is found), non-production environments will receive no database connection environment variables at all (since they're filtered out at line 300 and not restored on failure).

Per PR objectives, this appears intentional as a safety measure. Please confirm this is the desired fail-safe behavior.


326-329: LGTM!

The error handling appropriately treats Neon API failures as non-fatal, allowing the sync to continue with the filtered environment variables. This resilient approach ensures the build doesn't fail due to optional Neon integration issues.

Copy link
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: 1

🧹 Nitpick comments (3)
packages/build/src/extensions/core/vercelSyncEnvVars.ts (1)

83-100: Consider consolidating the filter and map into a single pass.

The value computation logic is duplicated between the filter (line 88) and map (line 94). A flatMap or reduce would eliminate the redundancy:

-      const filteredEnvs: EnvVar[] = data.envs
-        .filter((env: VercelEnvVar) => {
-          if (!env.target.includes(vercelEnvironment)) return false;
-          if (isBranchable && env.gitBranch && env.gitBranch !== branch) return false;
-          // When running in Vercel, prefer process.env but fall back to API value
-          const value = isVercelEnv ? (process.env[env.key] ?? env.value) : env.value;
-          if (!value) return false;
-          return true;
-        })
-        .map((env: VercelEnvVar) => {
-          // When running in Vercel, prefer process.env but fall back to API value
-          const value = isVercelEnv ? (process.env[env.key] ?? env.value) : env.value;
-          return {
-            name: env.key,
-            value,
-            isParentEnv: isBranchable && !env.gitBranch,
-          };
-        });
+      const filteredEnvs: EnvVar[] = data.envs.flatMap((env: VercelEnvVar) => {
+        if (!env.target.includes(vercelEnvironment)) return [];
+        if (isBranchable && env.gitBranch && env.gitBranch !== branch) return [];
+        // When running in Vercel, prefer process.env but fall back to API value
+        const value = isVercelEnv ? (process.env[env.key] ?? env.value) : env.value;
+        if (!value) return [];
+        return [{
+          name: env.key,
+          value,
+          isParentEnv: isBranchable && !env.gitBranch,
+        }];
+      });
packages/build/src/extensions/core/neonSyncEnvVars.ts (2)

139-143: Consider adding timeouts to Neon API calls.

The multiple fetch calls to the Neon API have no timeout configured. If the Neon API becomes slow or unresponsive, the build process could hang. Consider using AbortController with a timeout:

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000); // 30s timeout

try {
  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${neonAccessToken}` },
    signal: controller.signal,
  });
  // ...
} finally {
  clearTimeout(timeout);
}

This could be applied to all four API calls or extracted into a helper function.


251-261: Add a comment documenting the pooler host derivation logic.

The regex correctly transforms Neon endpoint hostnames to their pooled equivalents (e.g., ep-cool-darkness-123456.us-east-2.aws.neon.techep-cool-darkness-123456-pooler.us-east-2.aws.neon.tech). Add an inline comment explaining this transformation for future maintainability, such as: // Append "-pooler" before the region suffix to derive the pooled connection host.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49b2f68 and 6c89b7f.

📒 Files selected for processing (5)
  • docs/config/extensions/syncEnvVars.mdx (2 hunks)
  • docs/guides/examples/vercel-sync-env-vars.mdx (1 hunks)
  • packages/build/src/extensions/core.ts (1 hunks)
  • packages/build/src/extensions/core/neonSyncEnvVars.ts (1 hunks)
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/guides/examples/vercel-sync-env-vars.mdx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
🧠 Learnings (12)
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : When importing from `trigger.dev/core` in the webapp, use subpath exports from the package.json instead of importing from the root path

Applied to files:

  • packages/build/src/extensions/core.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Use build extensions in trigger.config.ts (additionalFiles, additionalPackages, aptGet, prismaExtension, etc.) to customize the build

Applied to files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
  • docs/config/extensions/syncEnvVars.mdx
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure build process in trigger.config.ts using `build` object with external packages, extensions, and JSX settings

Applied to files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
  • docs/config/extensions/syncEnvVars.mdx
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • packages/build/src/extensions/core.ts
  • docs/config/extensions/syncEnvVars.mdx
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export every task, including subtasks

Applied to files:

  • packages/build/src/extensions/core.ts
📚 Learning: 2025-08-19T09:49:07.011Z
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure Trigger.dev project in `trigger.config.ts` using `defineConfig()` with project ref and task directories

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Specify runtime environment (node or bun) in trigger.config.ts using the `runtime` property

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
📚 Learning: 2024-10-16T12:24:37.279Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 1407
File: apps/kubernetes-provider/src/index.ts:37-39
Timestamp: 2024-10-16T12:24:37.279Z
Learning: In Node.js, when assigning default values to environment variables using the `||` operator (e.g., `const VAR = process.env.VAR || 'default'`), empty strings are treated as falsy values, so the default value will be used without additional checks.

Applied to files:

  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
🧬 Code graph analysis (1)
packages/build/src/extensions/core/neonSyncEnvVars.ts (1)
packages/build/src/extensions/core/syncEnvVars.ts (1)
  • syncEnvVars (77-127)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
packages/build/src/extensions/core.ts (1)

6-6: LGTM!

The new export follows the established pattern and is correctly positioned alongside other core extensions.

packages/build/src/extensions/core/vercelSyncEnvVars.ts (1)

35-35: LGTM!

The isVercelEnv detection correctly identifies Vercel build environments by checking ctx.env.VERCEL.

docs/config/extensions/syncEnvVars.mdx (2)

83-89: LGTM!

The note clearly explains the Vercel environment detection behavior and how values are sourced from process.env instead of the API.


126-192: LGTM!

The syncNeonEnvVars documentation is comprehensive, covering prerequisites, environment-specific behavior, configuration options, and the list of synced environment variables. The examples follow the established pattern from syncVercelEnvVars.

packages/build/src/extensions/core/neonSyncEnvVars.ts (8)

4-26: LGTM!

The type definitions appropriately model the Neon API response structures and follow the existing pattern from vercelSyncEnvVars.ts.


28-45: LGTM!

The exported constant provides a comprehensive list of Neon database environment variables.


47-73: LGTM! Credentials are properly URL-encoded.

The function correctly uses encodeURIComponent for user and password values in all connection strings, preventing issues with special characters.


75-133: LGTM!

The function setup correctly:

  • Resolves configuration from multiple sources (options → process.env → context)
  • Skips Vercel environments where Neon's native integration handles syncing
  • Skips production environments as documented
  • Provides descriptive error messages for missing required inputs

135-166: LGTM!

The branch search logic correctly handles Neon's branch naming convention (e.g., preview/branch-name) with proper fallback to the raw branch name.


168-195: LGTM!

The endpoint selection logic correctly prioritizes write endpoints and falls back to the first available endpoint.


197-249: LGTM!

The database and role retrieval logic correctly:

  • Supports explicit database name selection or defaults to first database
  • Defaults role to database owner when not specified
  • Provides descriptive error messages for missing database or password

279-291: LGTM!

The error handling follows the established pattern, and the BuildExtension structure correctly delegates to the inner sync extension.

… syncing

Add a new `syncNeonEnvVars` build extension for syncing environment variables
from Neon database projects to Trigger.dev. The extension automatically detects
branches and builds appropriate PostgreSQL connection strings for non-production
environments (staging, dev, preview).

Features of `syncNeonEnvVars`:
- Fetches branch-specific database credentials from Neon API
- Generates all standard Postgres connection strings (DATABASE_URL, POSTGRES_URL,
  POSTGRES_PRISMA_URL, etc.) with both pooled and unpooled variants
- Supports custom database name, role name, and env var prefix options
- Skips automatically in Vercel environments (Neon's Vercel integration handles this)
- Skips for production environments (designed for preview/staging/dev branches)

Improvements to `syncVercelEnvVars`:
- When running in a Vercel build environment (detected via VERCEL env var),
  values are now read from process.env instead of the Vercel API response
- This ensures the build uses the actual runtime values Vercel provides
- Removed embedded Neon-specific logic (now handled by separate extension)
- Simplified and cleaned up the extension code

Documentation updates for both extensions with usage examples and configuration
options.
@0ski 0ski force-pushed the oo/gh-issue-2714 branch from 6c89b7f to 53f21e1 Compare December 3, 2025 15:03
Copy link
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: 0

🧹 Nitpick comments (1)
packages/build/src/extensions/core/neonSyncEnvVars.ts (1)

266-274: Avoid dropping valid but falsy env values in mapping loop.

The if (envVarMappings[neonEnvVar]) check will skip values like "" or "0" even if they are intentionally set. It’s safer to check for key presence instead:

-      for (const neonEnvVar of outputEnvVars) {
-        const prefixedKey = `${envVarPrefix}${neonEnvVar}`;
-        if (envVarMappings[neonEnvVar]) {
-          newEnvVars.push({
-            name: prefixedKey,
-            value: envVarMappings[neonEnvVar],
-          });
-        }
-      }
+      for (const neonEnvVar of outputEnvVars) {
+        const prefixedKey = `${envVarPrefix}${neonEnvVar}`;
+        if (neonEnvVar in envVarMappings) {
+          newEnvVars.push({
+            name: prefixedKey,
+            value: envVarMappings[neonEnvVar]!,
+          });
+        }
+      }

This makes the logic robust if additional Neon-related env vars or mappings ever need falsy-but-meaningful values.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c89b7f and 53f21e1.

📒 Files selected for processing (5)
  • docs/config/extensions/syncEnvVars.mdx (2 hunks)
  • docs/guides/examples/vercel-sync-env-vars.mdx (1 hunks)
  • packages/build/src/extensions/core.ts (1 hunks)
  • packages/build/src/extensions/core/neonSyncEnvVars.ts (1 hunks)
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/config/extensions/syncEnvVars.mdx
  • docs/guides/examples/vercel-sync-env-vars.mdx
  • packages/build/src/extensions/core/vercelSyncEnvVars.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
🧠 Learnings (6)
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : When importing from `trigger.dev/core` in the webapp, use subpath exports from the package.json instead of importing from the root path

Applied to files:

  • packages/build/src/extensions/core.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Use build extensions in trigger.config.ts (additionalFiles, additionalPackages, aptGet, prismaExtension, etc.) to customize the build

Applied to files:

  • packages/build/src/extensions/core.ts
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • packages/build/src/extensions/core.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export every task, including subtasks

Applied to files:

  • packages/build/src/extensions/core.ts
📚 Learning: 2025-08-19T09:49:07.011Z
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.

Applied to files:

  • packages/build/src/extensions/core/neonSyncEnvVars.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure build process in trigger.config.ts using `build` object with external packages, extensions, and JSX settings

Applied to files:

  • packages/build/src/extensions/core/neonSyncEnvVars.ts
🧬 Code graph analysis (1)
packages/build/src/extensions/core/neonSyncEnvVars.ts (1)
packages/build/src/extensions/core/syncEnvVars.ts (1)
  • syncEnvVars (77-127)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
packages/build/src/extensions/core.ts (1)

6-6: New Neon export wiring looks correct.

The added export cleanly exposes the Neon sync extension alongside the other core extensions and matches the existing export pattern.

packages/build/src/extensions/core/neonSyncEnvVars.ts (2)

28-73: Overall Neon env var derivation and host/pooler handling look solid.

The NEON_ENV_VARS list, SSL-focused connection strings, environment-to-branch naming (prod/staging/dev/preview), and poolerHost derivation (^([^.]+)\.$1-pooler.) all align with Neon’s documented patterns, and the code consistently uses encodeURIComponent for user/password values. The structure fits cleanly into the existing syncEnvVars extension model.

Also applies to: 120-176, 251-261


217-219: Fix unsafe options.databaseName access (can throw when options is omitted).

options is optional in syncNeonEnvVars, but Line 218 dereferences options.databaseName without optional chaining. If syncNeonEnvVars() is called with no argument, this will throw at runtime once this branch is reached.

Use a local databaseName variable or optional chaining consistently:

-      // Find the specified database or use the first one
-      const targetDatabase = options?.databaseName
-        ? databases.find((db) => db.name === options.databaseName)
-        : databases[0];
+      // Find the specified database or use the first one
+      const databaseName = options?.databaseName;
+      const targetDatabase = databaseName
+        ? databases.find((db) => db.name === databaseName)
+        : databases[0];

This keeps the runtime safe while preserving the intended behavior.

Likely an incorrect or invalid review comment.

Copy link
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: 0

🧹 Nitpick comments (3)
packages/build/src/extensions/core/neonSyncEnvVars.ts (2)

23-26: Align NeonRole typing with the Neon /reveal_password API response

Per the Neon API, GET /projects/{project_id}/branches/{branch_id}/roles/{role_name}/reveal_password returns a payload of the shape:

{ "password": "string" }

not a { name, password } object. You only consume password, so the current NeonRole type with a name field is slightly misleading.

To better reflect the API and avoid confusion:

-type NeonRole = {
-  name: string;
-  password?: string;
-};
+type NeonRolePasswordResponse = {
+  password?: string;
+};
@@
-      const rolePasswordData: NeonRole = await rolePasswordResponse.json();
+      const rolePasswordData: NeonRolePasswordResponse = await rolePasswordResponse.json();

Functionally this changes nothing today (because response.json() is any), but it documents the real API shape for future maintainers.

Also applies to: 232-248


4-4: Remove or use the unused isParentEnv field

EnvVar declares an optional isParentEnv property, but the extension never sets it when pushing newEnvVars. Unless you plan to route some of these Neon variables to parentEnv, this field can be dropped to keep the local type minimal and aligned with actual usage.

-type EnvVar = { name: string; value: string; isParentEnv?: boolean };
+type EnvVar = { name: string; value: string };

If parent env support is intended later, consider adding a small comment here explaining when isParentEnv should be used.

.changeset/funny-planes-remember.md (1)

1-5: Fix typo (env.process) and improve readability of the changeset summary

The summary line has a small typo and some concatenated words that make it harder to read:

  • It says env.process instead of process.env.
  • Several words run together: environments.New, variablesfrom, detectsbranches, non-productionenvironments.

Consider rewriting as:

-syncVercelEnvVars to skip API and read env vars directly from env.process for Vercel build environments.New syncNeonEnvVars build extension for syncing environment variablesfrom Neon database projects to Trigger.dev. The extension automatically detectsbranches and builds appropriate PostgreSQL connection strings for non-productionenvironments (staging, dev, preview).
+syncVercelEnvVars to skip the Vercel API and read env vars directly from process.env in Vercel build environments.
+
+New syncNeonEnvVars build extension for syncing environment variables from Neon database projects to Trigger.dev. The extension automatically detects branches and builds appropriate PostgreSQL connection strings for non-production environments (staging, dev, preview).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53f21e1 and 357aa99.

📒 Files selected for processing (3)
  • .changeset/funny-planes-remember.md (1 hunks)
  • docs/config/extensions/syncEnvVars.mdx (2 hunks)
  • packages/build/src/extensions/core/neonSyncEnvVars.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • packages/build/src/extensions/core/neonSyncEnvVars.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • packages/build/src/extensions/core/neonSyncEnvVars.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • packages/build/src/extensions/core/neonSyncEnvVars.ts
🧠 Learnings (10)
📚 Learning: 2025-08-19T09:49:07.011Z
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
  • .changeset/funny-planes-remember.md
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure Trigger.dev project in `trigger.config.ts` using `defineConfig()` with project ref and task directories

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
  • .changeset/funny-planes-remember.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Use build extensions in trigger.config.ts (additionalFiles, additionalPackages, aptGet, prismaExtension, etc.) to customize the build

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
  • .changeset/funny-planes-remember.md
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure build process in trigger.config.ts using `build` object with external packages, extensions, and JSX settings

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
  • .changeset/funny-planes-remember.md
  • packages/build/src/extensions/core/neonSyncEnvVars.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Specify runtime environment (node or bun) in trigger.config.ts using the `runtime` property

Applied to files:

  • docs/config/extensions/syncEnvVars.mdx
📚 Learning: 2025-10-08T11:48:12.327Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2593
File: packages/core/src/v3/workers/warmStartClient.ts:168-170
Timestamp: 2025-10-08T11:48:12.327Z
Learning: The trigger.dev runners execute only in Node 21 and 22 environments, so modern Node.js APIs like AbortSignal.any (introduced in v20.3.0) are supported.

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-02-10T10:56:31.402Z
Learnt from: zvictor
Repo: triggerdotdev/trigger.dev PR: 1686
File: packages/build/src/extensions/python.ts:110-116
Timestamp: 2025-02-10T10:56:31.402Z
Learning: In Docker build contexts for Trigger.dev extensions, avoid over-engineering security measures when handling user-provided configuration (like Python requirements) as the build context is already isolated and the content is user-controlled.

Applied to files:

  • .changeset/funny-planes-remember.md
🧬 Code graph analysis (1)
packages/build/src/extensions/core/neonSyncEnvVars.ts (1)
packages/build/src/extensions/core/syncEnvVars.ts (1)
  • syncEnvVars (77-127)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
packages/build/src/extensions/core/neonSyncEnvVars.ts (3)

47-73: Consider URL‑encoding the database name in generated connection strings

You correctly URL‑encode user and password, but database is interpolated raw into the connection URLs. If a database name ever contains characters that are not URL‑safe, the resulting connection strings could be invalid.

You can make this more robust by encoding database as well:

-  const { user, password, database, host, poolerHost } = options;
+  const { user, password, database, host, poolerHost } = options;
+  const encodedUser = encodeURIComponent(user);
+  const encodedPassword = encodeURIComponent(password);
+  const encodedDatabase = encodeURIComponent(database);

   return {
-    PGUSER: user,
-    PGPASSWORD: password,
-    PGDATABASE: database,
+    PGUSER: user,
+    PGPASSWORD: password,
+    PGDATABASE: database,
@@
-    DATABASE_URL: `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${poolerHost}/${database}?sslmode=require`,
-    DATABASE_URL_UNPOOLED: `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}/${database}?sslmode=require`,
-    POSTGRES_URL: `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${poolerHost}/${database}?sslmode=require`,
-    POSTGRES_URL_NO_SSL: `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${poolerHost}/${database}`,
-    POSTGRES_URL_NON_POOLING: `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}/${database}?sslmode=require`,
-    POSTGRES_PRISMA_URL: `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${poolerHost}/${database}?sslmode=require&pgbouncer=true&connect_timeout=15`,
+    DATABASE_URL: `postgresql://${encodedUser}:${encodedPassword}@${poolerHost}/${encodedDatabase}?sslmode=require`,
+    DATABASE_URL_UNPOOLED: `postgresql://${encodedUser}:${encodedPassword}@${host}/${encodedDatabase}?sslmode=require`,
+    POSTGRES_URL: `postgresql://${encodedUser}:${encodedPassword}@${poolerHost}/${encodedDatabase}?sslmode=require`,
+    POSTGRES_URL_NO_SSL: `postgresql://${encodedUser}:${encodedPassword}@${poolerHost}/${encodedDatabase}`,
+    POSTGRES_URL_NON_POOLING: `postgresql://${encodedUser}:${encodedPassword}@${host}/${encodedDatabase}?sslmode=require`,
+    POSTGRES_PRISMA_URL: `postgresql://${encodedUser}:${encodedPassword}@${poolerHost}/${encodedDatabase}?sslmode=require&pgbouncer=true&connect_timeout=15`,
   };

[uggest_recommended_refactor]


140-281: Neon branch → endpoint → database → role resolution flow looks solid

The overall flow—branch search with environment prefix, endpoint selection preferring a write endpoint, database selection (by name or first), role/password retrieval, and mapping into a well‑defined NEON_ENV_VARS set with optional prefix—is clear and matches the documented behavior (non‑prod, branch‑specific credentials, graceful no‑branch/no‑endpoint/no‑db fallbacks).

No additional issues spotted in this section beyond the smaller concerns noted in other comments.


92-95: The current implementation is correct and consistent with the established pattern in vercelSyncEnvVars.ts. Both extensions check only ctx.env.VERCEL for Vercel environment detection (line 35 in vercelSyncEnvVars.ts, line 93 in neonSyncEnvVars.ts). The suggested addition of process.env.VERCEL contradicts the actual pattern used in the Vercel extension and is not needed to align behavior.

Likely an incorrect or invalid review comment.

docs/config/extensions/syncEnvVars.mdx (2)

83-101: Vercel build behavior explanation is clear and matches intended behavior

The new note nicely explains that in Vercel builds values come from process.env while the Vercel API is only used to discover which vars exist, and it adds the missing “why” around Neon’s per‑preview provisioning phase. This should make the behavior of syncVercelEnvVars much less surprising.


137-211: syncNeonEnvVars docs line up well with the implementation

The new syncNeonEnvVars section correctly documents:

  • Required Neon configuration (NEON_ACCESS_TOKEN, NEON_PROJECT_ID or explicit options).
  • Skipping behavior for Vercel builds and prod environments.
  • Optional arguments (branch, databaseName, roleName, envVarPrefix).
  • The exact set of env vars it syncs, which matches NEON_ENV_VARS in the implementation.

Examples are consistent with the code and make it clear how to combine this with syncVercelEnvVars when running outside Vercel.

Copy link
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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 357aa99 and 8fcd930.

📒 Files selected for processing (1)
  • .changeset/funny-planes-remember.md (1 hunks)
🧰 Additional context used
🧠 Learnings (9)
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Use build extensions in trigger.config.ts (additionalFiles, additionalPackages, aptGet, prismaExtension, etc.) to customize the build

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-08-19T09:49:07.011Z
Learnt from: julienvanbeveren
Repo: triggerdotdev/trigger.dev PR: 2417
File: apps/webapp/app/routes/api.v1.projects.$projectRef.envvars.$slug.import.ts:56-61
Timestamp: 2025-08-19T09:49:07.011Z
Learning: In the Trigger.dev codebase, environment variables should default to `isSecret: false` when not explicitly marked as secrets in the syncEnvVars functionality. This is the intended behavior for both regular variables and parent variables.

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure build process in trigger.config.ts using `build` object with external packages, extensions, and JSX settings

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-10-08T11:48:12.327Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2593
File: packages/core/src/v3/workers/warmStartClient.ts:168-170
Timestamp: 2025-10-08T11:48:12.327Z
Learning: The trigger.dev runners execute only in Node 21 and 22 environments, so modern Node.js APIs like AbortSignal.any (introduced in v20.3.0) are supported.

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-02-10T10:56:31.402Z
Learnt from: zvictor
Repo: triggerdotdev/trigger.dev PR: 1686
File: packages/build/src/extensions/python.ts:110-116
Timestamp: 2025-02-10T10:56:31.402Z
Learning: In Docker build contexts for Trigger.dev extensions, avoid over-engineering security measures when handling user-provided configuration (like Python requirements) as the build context is already isolated and the content is user-controlled.

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Run `npx trigger.devlatest init` to initialize a Trigger.dev project

Applied to files:

  • .changeset/funny-planes-remember.md
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : When importing from `trigger.dev/core` in the webapp, use subpath exports from the package.json instead of importing from the root path

Applied to files:

  • .changeset/funny-planes-remember.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)

@0ski 0ski merged commit 05b5396 into main Dec 4, 2025
4 checks passed
@0ski 0ski deleted the oo/gh-issue-2714 branch December 4, 2025 15:26
@github-actions github-actions bot mentioned this pull request Dec 4, 2025
myftija pushed a commit that referenced this pull request Dec 5, 2025
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and publish to npm
yourself or [setup this action to publish
automatically](https://github.com/changesets/action#with-publishing). If
you're not ready to do a release yet, that's fine, whenever you add more
changesets to main, this PR will be updated.


# Releases
## trigger.dev@4.2.0

### Minor Changes

- feat(cli): upgrade bun deployments to v1.3.3
([#2756](#2756))

### Patch Changes

- fix(otel): exported logs and spans will now have matching trace IDs
([#2724](#2724))
- The `--force-local-build` flag is now renamed to just `--local-build`
([#2702](#2702))
- fix(cli): header will always print the correct profile
([#2728](#2728))
- feat: add ability to set custom resource properties through
trigger.config.ts or via the OTEL_RESOURCE_ATTRIBUTES env var
([#2704](#2704))
- feat(cli): implements content-addressable store for the dev CLI build
outputs, reducing disk usage
([#2725](#2725))
- Added support for native build server builds in the deploy command
(`--native-build-server`)
([#2702](#2702))
-   Updated dependencies:
    -   `@trigger.dev/build@4.2.0`
    -   `@trigger.dev/core@4.2.0`
    -   `@trigger.dev/schema-to-json@4.2.0`

## @trigger.dev/build@4.2.0

### Patch Changes

- syncVercelEnvVars to skip API and read env vars directly from
env.process for Vercel build environments. New syncNeonEnvVars build
extension for syncing environment variablesfrom Neon database projects
to Trigger.dev. The extension automatically detects branches and builds
appropriate PostgreSQL connection strings for non-production, non-dev
environments (staging, preview).
([#2729](#2729))
-   Updated dependencies:
    -   `@trigger.dev/core@4.2.0`

## @trigger.dev/core@4.2.0

### Patch Changes

- fix: prevent ERR_IPC_CHANNEL_CLOSED errors from causing an unhandled
exception on TaskRunProcess
([#2743](#2743))
- Added support for native build server builds in the deploy command
(`--native-build-server`)
([#2702](#2702))

## @trigger.dev/python@4.2.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/build@4.2.0`
    -   `@trigger.dev/sdk@4.2.0`
    -   `@trigger.dev/core@4.2.0`

## @trigger.dev/react-hooks@4.2.0

### Patch Changes

- fix: prevent infinite useEffect when passing an array of tags to
useRealtimeRunsWithTag
([#2705](#2705))
-   Updated dependencies:
    -   `@trigger.dev/core@4.2.0`

## @trigger.dev/redis-worker@4.2.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/core@4.2.0`

## @trigger.dev/rsc@4.2.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/core@4.2.0`

## @trigger.dev/schema-to-json@4.2.0

### Patch Changes

-   Updated dependencies:
    -   `@trigger.dev/core@4.2.0`

## @trigger.dev/sdk@4.2.0

### Patch Changes

- fix(sdk): Re-export schemaTask types to prevent the TypeScript error
TS2742: The inferred type of 'task' cannot be named without a reference
to '@trigger.dev/core/v3'. This is likely not portable.
([#2735](#2735))
- feat: add ability to set custom resource properties through
trigger.config.ts or via the OTEL_RESOURCE_ATTRIBUTES env var
([#2704](#2704))
-   Updated dependencies:
    -   `@trigger.dev/core@4.2.0`

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
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.

bug: syncVercelEnvVars syncs production env var for preview deployment when using NeonDB vercel integration

4 participants