Skip to content

Commit 99f0787

Browse files
authored
feat(cli,webapp): default new projects to node-24 (#4649)
1 parent 7d9f1a3 commit 99f0787

16 files changed

Lines changed: 85 additions & 28 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trigger.dev": patch
3+
---
4+
5+
New projects created with `trigger init` use Node.js 24 by default. Deployments without explicit `runtime` now use their project's configured default runtime.

apps/webapp/app/models/project.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ export async function createProject(
113113
// for historical rows; the V1->V2 upgrade guards on worker-register / deploy
114114
// stay in place to migrate existing legacy projects.
115115
engine: "V2",
116+
defaultRuntime: "node-24",
116117
onboardingData,
117118
},
118119
include: {

apps/webapp/app/models/runtimeEnvironment.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { controlPlaneResolver } from "~/v3/runOpsMigration/controlPlaneResolver.
66
import { logger } from "~/services/logger.server";
77
import { getUsername } from "~/utils/username";
88
import { hashApiKey } from "~/utils/apiKeys";
9+
import { BuildRuntime } from "@trigger.dev/core/v3";
910
import { isAdditionalApiKey } from "@trigger.dev/core/v3/apiKeys";
1011
import { isDefaultDevBranch, sanitizeBranchName } from "@trigger.dev/core/v3/utils/gitBranch";
1112
import { scopesGrantFullAccess } from "@trigger.dev/rbac";
@@ -77,6 +78,7 @@ export function toAuthenticated(
7778
defaultWorkerGroupId: env.project.defaultWorkerGroupId,
7879
organizationId: env.project.organizationId,
7980
builderProjectId: env.project.builderProjectId,
81+
defaultRuntime: BuildRuntime.nullable().safeParse(env.project.defaultRuntime).data ?? null,
8082
},
8183
organization: {
8284
id: env.organization.id,

apps/webapp/app/routes/api.v1.projects.$projectRef.$env.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { json, type LoaderFunctionArgs } from "@remix-run/server-runtime";
2-
import { type GetProjectEnvResponse } from "@trigger.dev/core/v3";
2+
import { BuildRuntime, type GetProjectEnvResponse } from "@trigger.dev/core/v3";
33
import { z } from "zod";
44
import { env as processEnv } from "~/env.server";
55
import {
@@ -65,6 +65,8 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
6565
name: environment.project.name,
6666
apiUrl: processEnv.API_ORIGIN ?? processEnv.APP_ORIGIN,
6767
projectId: environment.project.id,
68+
defaultRuntime:
69+
BuildRuntime.nullable().safeParse(environment.project.defaultRuntime ?? null).data ?? null,
6870
};
6971

7072
return json(result);

apps/webapp/app/routes/api.v1.projects.$projectRef.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { json } from "@remix-run/server-runtime";
2-
import type { GetProjectResponseBody } from "@trigger.dev/core/v3";
2+
import { BuildRuntime, type GetProjectResponseBody } from "@trigger.dev/core/v3";
33
import { z } from "zod";
44
import { prisma } from "~/db.server";
55
import { DeleteProjectService } from "~/services/deleteProject.server";
@@ -53,6 +53,8 @@ export const loader = createLoaderPATApiRoute(
5353
slug: project.slug,
5454
createdAt: project.createdAt,
5555
defaultRegion: project.defaultWorkerGroup?.name ?? null,
56+
defaultRuntime:
57+
BuildRuntime.nullable().safeParse(project.defaultRuntime ?? null).data ?? null,
5658
organization: {
5759
id: project.organization.id,
5860
title: project.organization.title,

apps/webapp/app/v3/services/initializeDeployment.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ export class InitializeDeploymentService extends BaseService {
253253
imagePlatform: env.DEPLOY_IMAGE_PLATFORM,
254254
git: payload.gitMeta ?? undefined,
255255
commitSHA: payload.gitMeta?.commitSha ?? undefined,
256-
runtime: payload.runtime ?? undefined,
256+
runtime: payload.runtime ?? environment.project.defaultRuntime ?? undefined,
257257
triggeredVia: payload.triggeredVia ?? undefined,
258258
startedAt: initialStatus === "BUILDING" ? new Date() : undefined,
259259
};

apps/webapp/test/projectEnvironmentCredentialRoute.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const environment = {
3737
project: {
3838
id: "proj_123",
3939
name: "Example project",
40+
defaultRuntime: "node-24",
4041
},
4142
};
4243

@@ -82,6 +83,7 @@ describe("project environment credential response", () => {
8283
await expect(responseJson(response)).resolves.toMatchObject({
8384
apiKey: "tr_prod_sk_presented",
8485
projectId: "proj_123",
86+
defaultRuntime: "node-24",
8587
});
8688
expect(mocks.authorizePatEnvironmentAccess).not.toHaveBeenCalled();
8789
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "Project" ADD COLUMN "defaultRuntime" TEXT;

internal-packages/database/prisma/schema.prisma

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,9 @@ model Project {
474474
/// Set the first time the CLI `init` command completes against this project. Drives the dev onboarding progress.
475475
initializedAt DateTime?
476476
477+
/// Runtime used when a deployment config does not specify one. Null preserves the legacy Node 20 fallback.
478+
defaultRuntime String?
479+
477480
version ProjectVersion @default(V2)
478481
engine RunEngineVersion @default(V1)
479482
@@ -790,26 +793,26 @@ model WebhookEndpoint {
790793
791794
source String // provider tag e.g. "stripe","slack","github"
792795
handlerWebhookId String // declared webhook() id (string ref, GOLDEN LAW, no relation)
793-
routingTarget Json // RoutingTarget tagged union ({ type: "task" } | { type: "session" })
794-
verifierArtifact Json // VerifierArtifact tagged union (config|preset in P1)
796+
routingTarget Json // RoutingTarget tagged union ({ type: "task" } | { type: "session" })
797+
verifierArtifact Json // VerifierArtifact tagged union (config|preset in P1)
795798
filter String? // source filter DSL string (display/round-trip)
796-
filterAst Json? // compiled FilterAst, evaluated at ingest; null = route all
797-
filterAstVersion Int? // re-parse `filter` on a format bump
798-
metadata Json @default("{}") // arbitrary user metadata; flows into the webhook task
799+
filterAst Json? // compiled FilterAst, evaluated at ingest; null = route all
800+
filterAstVersion Int? // re-parse `filter` on a format bump
801+
metadata Json @default("{}") // arbitrary user metadata; flows into the webhook task
799802
800803
// who supplies the secret/key; drives the Connect UI (paste vs generate). From the source.
801804
secretProvisioning String @default("either") // "provider" | "integrator" | "either"
802805
803806
/// SecretReference.key string. Plain String, NO @relation -> no FK to SecretReference.
804807
signingSecretKey String?
805808
806-
status WebhookEndpointStatus @default(ACTIVE)
809+
status WebhookEndpointStatus @default(ACTIVE)
807810
/// When an operator disabled the endpoint via the dashboard/API. Null means the declarative sync
808811
/// owns the status: a redeploy that re-declares a previously-removed (auto-deactivated) webhook
809812
/// reactivates it. Non-null means the operator disabled it, so the sync leaves the status alone.
810813
manuallyDeactivatedAt DateTime?
811-
createdAt DateTime @default(now())
812-
updatedAt DateTime @updatedAt
814+
createdAt DateTime @default(now())
815+
updatedAt DateTime @updatedAt
813816
814817
@@unique([runtimeEnvironmentId, handlerWebhookId, endpointTenantId, endpointExternalRef]) // deploy-sync key
815818
@@index([runtimeEnvironmentId, source])
@@ -842,8 +845,8 @@ model WebhookDelivery {
842845
/// Set from the x-trigger-test ingress header; marks console/test-send deliveries so the list can filter them.
843846
isTest Boolean @default(false)
844847
845-
parsedEvent Json? // size-capped snapshot of the verified event (full event lives in ClickHouse)
846-
headers Json? // inbound request headers, surfaced to the webhook task via onEvent({ headers })
848+
parsedEvent Json? // size-capped snapshot of the verified event (full event lives in ClickHouse)
849+
headers Json? // inbound request headers, surfaced to the webhook task via onEvent({ headers })
847850
rawBodyHash String? // sha256 of raw bytes; cheap P2 replay anchor
848851
errorMessage String?
849852
filterReason String? // why a FILTERED delivery was not routed (failing clause + actual value)
@@ -2370,8 +2373,8 @@ model TaskSchedule {
23702373
timezone String @default("UTC")
23712374
23722375
// Cron spread
2373-
windowDurationSeconds Int?
2374-
windowPercentage Int?
2376+
windowDurationSeconds Int?
2377+
windowPercentage Int?
23752378
23762379
///Can be provided by the user then accessed inside a run
23772380
externalId String?

packages/cli-v3/src/commands/deploy.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
300300
logger.debug("Using project ref from env", { ref: envVars.TRIGGER_PROJECT_REF });
301301
}
302302

303-
const resolvedConfig = await loadConfig({
303+
let resolvedConfig = await loadConfig({
304304
cwd: projectPath,
305305
overrides: { project: options.projectRef ?? envVars.TRIGGER_PROJECT_REF },
306306
configFile: options.config,
@@ -364,6 +364,10 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
364364
throw new Error("Failed to get project client");
365365
}
366366

367+
if (!resolvedConfig.runtimeWasExplicit && projectClient.defaultRuntime) {
368+
resolvedConfig.runtime = projectClient.defaultRuntime;
369+
}
370+
367371
if (options.nativeBuildServer) {
368372
await handleNativeBuildServerDeploy({
369373
apiClient: projectClient.client,

0 commit comments

Comments
 (0)