Skip to content

gen: a feature-flag that keeps the migration engine off Client - #4

Merged
lesomnus merged 1 commit into
masterfrom
no-client-schema
Sep 6, 2026
Merged

lesomnus merged 1 commit into
masterfrom
no-client-schema

Conversation

@lesomnus

@lesomnus lesomnus commented Sep 6, 2026

Copy link
Copy Markdown
Member

Client holds Schema *migrate.Schema and NewClient builds one. That is an import, and the linker follows imports: a generated package pulls in dialect/sql/schema, which pulls in Atlas — its diff planner, all three of its SQL dialects, and the HCL parser those import for a schema language most programs never write.

A program that never migrates carries all of it anyway.

Measured on an app compiled to GOOS=js GOARCH=wasm and served from the page it serves, where the database is created once from a script and never migrated:

56,941,319   before
46,435,965   with the flag

10.5 MB of a 57 MB module, gzip 10.9 MB → 8.77 MB, linked to answer a question the program does not ask. Atlas, HCL and cty symbols go from present to zero.

What it does

sql/no-client-schema drops the Schema field and its init. The caller says it instead, with the driver it already had to build the client:

migrate.NewSchema(drv).Create(ctx)

migrate is generated either way, so Tables and versioned migrations are unaffected — this is only about what Client carries.

Off by default

Every generated client in this repository is unchanged, and that is checked rather than asserted: go generate ./idtype/ent/ under entc/integration with the flag off rewrites no .go file at all. enttest is conditioned the same way, so its output is byte-identical too.

Checked

  • go build ./... — exit 0
  • go test ./entc/gen/... — exit 0
  • regeneration with the flag off — no generated file changes
  • regeneration with the flag on, in a downstream app — builds, its own test suite passes, and its sandbox passes a browser test on the smaller module

🤖 Generated with Claude Code

https://claude.ai/code/session_01UbzZbDZvDr4DCiEamJf585

`Client.Schema` is a `*migrate.Schema` and `NewClient` builds one, which is
an import, and the linker follows imports: a generated package pulls in
`dialect/sql/schema`, which pulls in Atlas -- its diff planner, all three
SQL dialects, and the HCL parser those import for a schema language most
programs never write.

A program that never migrates carries all of it. Measured on an app
compiled to `GOOS=js GOARCH=wasm` and served from its own page: 10.5 MB of
a 56.9 MB module, linked to answer a question the program does not ask.

`sql/no-client-schema` drops the field and its init. The caller says it
instead, with the driver it already had to build the client:

	migrate.NewSchema(drv).Create(ctx)

Off by default, so every generated client in this repository is unchanged
-- checked: with the flag off, generation is byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UbzZbDZvDr4DCiEamJf585
@lesomnus

lesomnus commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

Reviewed and verified locally against master (which now carries the CI fixes this PR's red run was waiting on — the lint job could not load its config on Go 1.27, and mariadb:11.4 never became healthy because the health command asked for a mysqladmin that image does not ship).

What I checked, rather than took from the description:

  • Flag off changes nothing. Merged master in and regenerated all three modules; git status is empty. The generate job enforces the same thing on every push, so this stays true rather than being true today.
  • Flag on does what it says. Regenerated entc/integration/idtype/ent with --feature sql/no-client-schema: the Schema field is gone, c.Schema = migrate.NewSchema(...) is gone from init, the .../ent/migrate import is gone from client.go, and the package builds.
  • enttest follows. It renders migrate.Create(ctx, migrate.NewSchema(c.Driver()), ...), which works because Client.Driver() exists here (d7f47a8b8). This flag is a coherent extension of that commit and would be harder upstream.
  • The failure mode is a compile error. idtype_test.go uses client.Schema and stops compiling with the flag on. That is the contract stated in the doc comment, and it is the right way for it to fail — a caller is told, not silently handed a client that cannot migrate.

Three guard points and all three are covered: the field, its init, and the import. Experimental and off by default, so nothing that does not ask for it can be affected.

One gap, filed as #5 rather than held against this: nothing in this repository generates with the flag on, so a later template change could break the flag path and no test would say so. That is the exact shape of several things found in this repository today — a view definition, a migration directory, eight examples — each wrong for as long as nothing ran it.

@lesomnus
lesomnus merged commit 111aa8b into master Sep 6, 2026
2 of 4 checks passed
@lesomnus
lesomnus deleted the no-client-schema branch September 6, 2026 21:51
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.

1 participant