Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .server-changes/native-build-server-opt-out.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
area: webapp
type: improvement
---

Make the native build server the default in project build settings. It's now opt-out, stored as a new `disableNativeBuildServer` key. Also clarifies in the UI that build settings apply to GitHub-triggered and native build server deployments.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ const UpdateBuildSettingsFormSchema = z.object({
.refine((val) => !val || val.length <= 500, {
message: "Pre-build command must not exceed 500 characters",
}),
// Positive checkbox in the UI ("Use native build server"). It is checked by
// default; we store the inverse as `disableNativeBuildServer`.
useNativeBuildServer: z
.string()
.optional()
Expand Down Expand Up @@ -152,7 +154,8 @@ export const action: ActionFunction = async ({ request, params }) => {
installCommand: installCommand || undefined,
preBuildCommand: preBuildCommand || undefined,
triggerConfigFilePath: triggerConfigFilePath || undefined,
useNativeBuildServer: useNativeBuildServer,
// Native build server is the default, so we only persist the opt-out.
disableNativeBuildServer: useNativeBuildServer ? undefined : true,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

if (resultOrFail.isErr()) {
Expand Down Expand Up @@ -321,6 +324,10 @@ export default function IntegrationsSettingsPage() {

<div>
<Header2 spacing>Build settings</Header2>
<Hint className="mb-2">
These settings apply to GitHub-triggered deployments and deployments built with
the native build server.
</Hint>
<div className="w-full rounded-sm border border-grid-dimmed p-4">
<BuildSettingsForm buildSettings={buildSettings ?? {}} />
</div>
Expand Down Expand Up @@ -362,21 +369,24 @@ function BuildSettingsForm({ buildSettings }: { buildSettings: BuildSettings })
const navigation = useNavigation();

const [hasBuildSettingsChanges, setHasBuildSettingsChanges] = useState(false);
// The native build server is enabled by default; it's only off when the
// project has explicitly opted out via `disableNativeBuildServer`.
const nativeBuildServerEnabled = buildSettings?.disableNativeBuildServer !== true;
const [buildSettingsValues, setBuildSettingsValues] = useState({
preBuildCommand: buildSettings?.preBuildCommand || "",
installCommand: buildSettings?.installCommand || "",
triggerConfigFilePath: buildSettings?.triggerConfigFilePath || "",
useNativeBuildServer: buildSettings?.useNativeBuildServer || false,
useNativeBuildServer: nativeBuildServerEnabled,
});

useEffect(() => {
const hasChanges =
buildSettingsValues.preBuildCommand !== (buildSettings?.preBuildCommand || "") ||
buildSettingsValues.installCommand !== (buildSettings?.installCommand || "") ||
buildSettingsValues.triggerConfigFilePath !== (buildSettings?.triggerConfigFilePath || "") ||
buildSettingsValues.useNativeBuildServer !== (buildSettings?.useNativeBuildServer || false);
buildSettingsValues.useNativeBuildServer !== nativeBuildServerEnabled;
setHasBuildSettingsChanges(hasChanges);
}, [buildSettingsValues, buildSettings]);
}, [buildSettingsValues, buildSettings, nativeBuildServerEnabled]);

const [buildSettingsForm, fields] = useForm({
id: "update-build-settings",
Expand Down Expand Up @@ -462,7 +472,7 @@ function BuildSettingsForm({ buildSettings }: { buildSettings: BuildSettings })
{...conform.input(fields.useNativeBuildServer, { type: "checkbox" })}
label="Use native build server"
variant="simple/small"
defaultChecked={buildSettings?.useNativeBuildServer || false}
defaultChecked={nativeBuildServerEnabled}
onChange={(isChecked) => {
setBuildSettingsValues((prev) => ({
...prev,
Expand All @@ -471,8 +481,8 @@ function BuildSettingsForm({ buildSettings }: { buildSettings: BuildSettings })
}}
/>
<Hint>
Native build server builds do not rely on external build providers and will become the
default in the future. Version 4.2.0 or newer is required.
Native build server builds don't rely on external build providers and are used by
default. Requires version 4.2.0 or newer.
</Hint>
<FormError id={fields.useNativeBuildServer.errorId}>
{fields.useNativeBuildServer.error}
Expand Down
4 changes: 3 additions & 1 deletion apps/webapp/app/v3/buildSettings.ts

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.

🚩 No server-side consumers of the native build server flag found

Searched the entire codebase for consumers of useNativeBuildServer or disableNativeBuildServer outside the settings UI route. Found zero usages in deployment services, GitHub-triggered deploy flows, or any backend build logic. The flag appears to be stored in the database but only read back by the settings UI presenter (apps/webapp/app/services/projectSettingsPresenter.server.ts:31). The CLI's nativeBuildServer option in packages/cli-v3/src/commands/deploy.ts:83 is a separate CLI flag (z.boolean().default(false)) that doesn't read from the server's buildSettings. This means the schema rename has no backend behavioral impact — it's purely a UI/storage concern. However, this raises the question: is the disableNativeBuildServer flag actually consumed by the GitHub-triggered deployment flow to decide whether to use the native build server? If not, this setting may be a no-op for that deployment path.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ export const BuildSettingsSchema = z.object({
triggerConfigFilePath: z.string().optional(),
installCommand: z.string().optional(),
preBuildCommand: z.string().optional(),
useNativeBuildServer: z.boolean().optional(),
// Opt-out flag: the native build server is used by default. Only set when a
// project explicitly disables it. Absence means native build server enabled.
disableNativeBuildServer: z.boolean().optional(),
Comment on lines +7 to +9

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.

🚩 Implicit data migration via Zod key stripping — old useNativeBuildServer values silently dropped

Existing database records may contain { useNativeBuildServer: true } or { useNativeBuildServer: false } in the buildSettings JSON column. After the schema rename to disableNativeBuildServer at apps/webapp/app/v3/buildSettings.ts:9, Zod's default .object() behavior strips unrecognized keys during safeParse at apps/webapp/app/services/projectSettingsPresenter.server.ts:31. This means:

  • Projects with useNativeBuildServer: true → parsed as {}disableNativeBuildServer absent → treated as enabled ✓
  • Projects with useNativeBuildServer: false → parsed as {}disableNativeBuildServer absent → treated as enabled (was previously disabled)
  • Projects with no buildSettings at all → treated as enabled (was previously disabled)

This is the intended behavior per the PR description ("make native build server the default"), but it's worth noting that there is no explicit data migration — the behavior change happens implicitly through the schema rename. Projects that previously had native build server explicitly disabled will have it silently re-enabled. This is presumably acceptable since the PR is intentionally flipping the default, but reviewers should confirm this is the desired rollout strategy.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

});

export type BuildSettings = z.infer<typeof BuildSettingsSchema>;