Skip to content

perf(deps): let a build omit the datasource drivers and GraphQL engine it does not use - #4167

Open
aryanmehrotra wants to merge 5 commits into
developmentfrom
perf/optional-datasources-graphql
Open

aryanmehrotra wants to merge 5 commits into
developmentfrom
perf/optional-datasources-graphql

Conversation

@aryanmehrotra

@aryanmehrotra aryanmehrotra commented Sep 8, 2026

Copy link
Copy Markdown
Member

Description:

Three opt-in build tags. A build that sets none of them is byte-for-byte what it is today.

tag omits
gofr_nosqldrivers the blank-imported SQL drivers
gofr_nopubsub the Kafka / Google / MQTT client implementations
gofr_nographql graphql-go and gqlparser

Measured on a minimal GoFr service (gofr.New, one route, Run):

build binary packages
default 57.10 MB 831
gofr_nosqldrivers 50.96 MB 787
gofr_nopubsub 48.23 MB 618
gofr_nographql 56.32 MB 811
all three 41.26 MB 554

−15.84 MB (−27.7%), −277 packages. Idle RSS drops too, driven by the drivers.

Why the drivers cost so much. modernc.org/sqlite is blank-imported for driver registration and brings modernc.org/libc, whose netdb init parses embedded copies of /etc/protocols and /etc/services into permanent Go structs — about 1.7 MB of retained heap, roughly half the process's fixed heap floor. None of it is reachable from the HTTP path. The three pub/sub clients bring 213 packages between them, most of it Google Pub/Sub's gRPC and auth stack.

The mechanism, and the part that is easy to get wrong. Making a subsystem optional takes two things: an interface on the consumer naming only the methods it calls, and a build tag on the concrete file.

⚠️ The interface alone does nothing. Extracting graphQLRunner left all the graphql packages linked until graphql.go itself carried the tag — the concrete file still compiles the library in.

Breaking Changes (if applicable):

None. Every tag is opt-in and the default build is unchanged.

GraphQLQuery and GraphQLMutation name only GoFr's own Handler, so the exported surface is identical in both builds.

Verified against development: identical go doc -all across 6 packages, and an identical linked-package list.

A build that does set gofr_nographql still compiles a user's GraphQL calls. Registering a resolver logs an error naming the tag rather than failing silently, and enabled() keeps App from routing /graphql and the playground against a handler this build cannot provide.

⚠️ Without that guard setupGraphQL registers a nil handler and the first POST /graphql panics. TestGraphQLDisabled_SetupRegistersNoRoute fails if the guard is removed.

Additional Information:

  • No new dependencies — this PR only removes linkage.
  • A new Slim Build Tags 🪶 CI job builds and tests every tag combination. Half the code these tags add is compiled only when the tags are set; without that job nothing would ever build it.
  • noopResponder moves from responder.go into graphql.go, its only user. It cannot stay: responder.go also holds the exported Responder interface so it cannot carry the tag, and leaving it there makes it dead code in a tagged build — which golangci-lint reports as unused, failing the lint gate for anyone who sets the tag.
  • configTrue is declared inside pubsub_backends.go for the same reason: an untagged home would leave it unused under gofr_nopubsub.

Checklist:

  • I have formatted my code using goimport and golangci-lint.
  • All new code is covered by unit tests.
  • This PR does not decrease the overall code coverage.
  • I have reviewed the code comments and documentation for clarity.

A GoFr binary links every datasource driver whether or not the service
opens one. Measured on a plain HTTP service: 827 packages, 57.8 MB of
binary and 31.6 MB of resident memory at rest, against 19.6-20.9 MB for
every other Go HTTP framework at the same observability.

Two things account for it, and neither is reachable from the HTTP path.
modernc.org/sqlite is blank-imported for driver registration and brings
modernc.org/libc, whose netdb init parses embedded copies of /etc/protocols
and /etc/services into permanent Go structs -- 1.69 MB of retained heap,
roughly half the process's fixed heap floor. The three concrete pub/sub
clients bring 212 packages between them, most of it Google Pub/Sub's grpc
and auth stack.

Both are now behind build tags. The default build is unchanged: it links
the same 827 packages as before, byte for byte, so a user who does nothing
sees nothing. A service that uses neither can build with

    -tags 'gofr_nosqldrivers gofr_nopubsub'

and gets 42.7 MB of binary (-26%), 22.8 MB idle RSS (-28%) and a 1.5 MB
heap floor (-68%) -- within about 2 MB of gin and gorilla.

Nothing is pinned by a public type, which is what makes this possible
without an API change: Container.PubSub is the pubsub.Client interface, and
the drivers are blank imports whose only effect is init(). Container.SQL and
Container.Redis keep their concrete types and are untouched.

A tagged build that configures an omitted backend still starts and serves.
It logs one ERROR naming the tag for pub/sub, or database/sql's own
'unknown driver' for a dialect, and leaves the client nil -- the same state
an unconfigured datasource already produces. The stubs return an untyped
nil, so both Close and Health take their nil branches. (Health guards SQL
and Redis with isNil but PubSub with a plain != nil, which a typed-nil
would defeat; nothing here produces one, but see the follow-up.) Verified by running a tagged binary
under each of PUBSUB_BACKEND=KAFKA, GOOGLE and MQTT and DB_DIALECT=sqlite:
all four serve correctly and complain loudly.

Tests run in both configurations. The sql suite imports its own drivers, and
the two container tests that assert on a concrete client skip when the
backends are not linked.
Every GoFr binary links graphql-go and gqlparser whether or not the
service registers a resolver: 20 packages and 0.78 MB of binary that a
service with no GraphQL never executes.

-tags gofr_nographql now leaves them out. Measured on a minimal GoFr
service (gofr.New, one route, Run):

    default                57.10 MB   831 packages
    -tags gofr_nographql   56.32 MB   811 packages

Idle RSS is unchanged, and that is expected: the engine allocates
nothing until a resolver is registered, so what the tag saves is text,
not heap. The saving compounds with the datasource tags -- both of those
plus this one take the same service to 41.26 MB and 554 packages.

The mechanism is the one the pub/sub backends already use, with one
addition. App's field becomes an interface, graphQLRunner, naming the
five methods App actually calls; graphql.go, which holds the concrete
manager, carries the tag. Both halves are needed -- the interface alone
changes nothing, because the concrete file still compiles the library
in. That is the general rule for making any subsystem optional.

Nothing changes for a user who does not set the tag: GraphQLQuery and
GraphQLMutation name only GoFr's own Handler, so the exported surface is
byte-identical in both builds, and the default build links the same
packages it always did.

A build that does set the tag still compiles a user's GraphQL calls.
Registering a resolver logs an error naming the tag rather than failing
silently, and enabled() keeps App from routing /graphql and the
playground against a handler this build cannot provide. Without that
guard setupGraphQL registers a nil handler and the first POST /graphql
panics; TestGraphQLDisabled_SetupRegistersNoRoute fails if the guard is
removed.

noopResponder moves from responder.go into graphql.go, its only user. It
cannot stay: responder.go also holds the exported Responder interface,
so it cannot carry the tag, and leaving the type there makes it dead
code in a tagged build -- which golangci-lint reports as unused, failing
the lint gate for anyone who sets the tag.

The Slim Build Tags CI job now covers gofr_nographql alongside the
datasource tags, and runs the stub tests, which exist only under it.
@aryanmehrotra
aryanmehrotra force-pushed the perf/optional-datasources-graphql branch from 7989966 to a969749 Compare September 8, 2026 08:50
@akshat-kumar-singhal

Copy link
Copy Markdown
Contributor

A downstream data point for gofr_nopubsub, on a different axis from binary size.

We run a GoFr service that uses no pub/sub at all. Because pkg/gofr/container/container.go imports gofr.dev/pkg/gofr/datasource/pubsub/google unconditionally, go mod why gives us this on v1.60.1:

our-service/cmd/...
 → gofr.dev/pkg/gofr
 → gofr.dev/pkg/gofr/container
 → gofr.dev/pkg/gofr/datasource/pubsub/google
 → cloud.google.com/go/pubsub
 → google.golang.org/api/transport/http
 → google.golang.org/api/internal/cert
 → github.com/googleapis/enterprise-certificate-proxy

Last week that last one broke a deploy for us. Google moved the enterprise-certificate-proxy v0.3.19 tag after publication:

$ curl -s https://proxy.golang.org/github.com/googleapis/enterprise-certificate-proxy/@v/v0.3.19.mod | grep toolchain
toolchain go1.25.8

$ curl -s https://raw.githubusercontent.com/googleapis/enterprise-certificate-proxy/v0.3.19/go.mod | grep toolchain
toolchain go1.26.5

Our go.sum matched sum.golang.org throughout, and the proxy-based build that actually ships was correct the whole time — the checksum database is append-only, so only a build resolving from VCS could see it. But we keep a GOPROXY=direct resilience build, and that job failed go mod download on the mismatch and could never pass again at that version. We pinned forward and moved on.

None of that is GoFr's doing. The point is only where we happened to be standing when it landed: we absorbed it for a module we never import, reached solely through a pub/sub client we don't use, feeding a client-certificate feature we have never enabled — nothing in our tree, infra or workflows sets GOOGLE_API_USE_CLIENT_CERTIFICATE or ships a certificate_config.json, so the package is linked into every binary and switched on in none of them.

So the 213 packages gofr_nopubsub removes aren't only 8.9 MB of binary. They're 213 packages of supply-chain surface that a non-pub/sub service carries permanently, and that cost recurs on its own schedule — independent of binary size, and not something a consumer can opt out of today.

For what it's worth, this also reads as a continuation of existing practice rather than a new idea: gofr.dev/pkg/gofr/metrics/exporters/gcp is already a separate module we require and version explicitly, while pubsub/*, redis, sql and file are in core.

Happy to build our service against the tag and report back if that would be useful.

@aryanmehrotra

Copy link
Copy Markdown
Member Author

Thanks, this is a useful data point, and yes please: building your service against this branch and reporting back would help a lot.

The branch head is a969749b7, so go get gofr.dev@a969749b743012ce06b24b05f8c7061fd56b5e53 pins it. The numbers that would matter most:

  1. Binary size and package count for your real service, default vs -tags gofr_nopubsub (and all three tags if the service allows it): ls -l on the binary, plus go list -deps -tags gofr_nopubsub ./... | wc -l.
  2. Linked packages: go list -deps -tags gofr_nopubsub ./... | grep enterprise-certificate-proxy should print nothing.
  3. Idle RSS, if you have a quick way to take it.
  4. Anything that fails to compile or behaves differently under the tag.

One limit to be upfront about, since it bears directly on the failure you hit. I reproduced it against a minimal service on this branch:

default gofr_nopubsub
enterprise-certificate-proxy packages in go list -deps 2 0
present in go.sum / go mod why -m yes yes
fetched by go mod download yes yes

The tag removes the code from the build graph, so it is no longer linked into or compiled into your binary. It does not remove it from the module graph. cloud.google.com/go/pubsub is still a requirement in GoFr's go.mod, and go mod download and go mod tidy resolve modules across all build tags. So your GOPROXY=direct job would still have fetched v0.3.19 and failed on the re-tag, tag or not.

Removing it from the module graph as well would mean moving the pub/sub clients into their own modules, the way metrics/exporters/gcp already is. That's a larger, breaking change and out of scope here, but your report is a good argument for it as a follow-up.

@PiyushSingh-ZS PiyushSingh-ZS left a comment

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.

The engineering here is careful and the measurements are worth having. Before line-level review, though, I think there is a mechanism question that maintainers should rule on, because it decides whether most of this diff is the right shape.

What is clearly right

The warning that the interface alone does nothing is the most valuable thing in the PR:

Extracting graphQLRunner left all the graphql packages linked until graphql.go itself carried the tag -- the concrete file still compiles the library in.

That is the failure mode people ship by accident and then wonder why the binary did not shrink. Catching it and stating it plainly is a real contribution regardless of what happens to the rest.

The modernc.org/libc finding is also specific and verifiable: netdb init parsing embedded /etc/protocols and /etc/services into permanent Go structs, retained for the life of the process, unreachable from the HTTP path.


The mechanism question: build tags, or the pattern the repo already has?

GoFr already ships 25 nested go.mod modules under pkg/gofr/datasource/mongo, cassandra, clickhouse, scylladb, elasticsearch, oracle, surrealdb, dgraph, file/s3, file/gcs, kv-store/badger, and directly relevant here: pubsub/nats, pubsub/sqs, pubsub/eventhub.

Three pub/sub backends are already separate modules. Kafka, Google and MQTT are the outliers that stayed in the root module. So for gofr_nopubsub — by some distance the largest win in this PR, 213 packages and 8.9 MB — there is an existing, proven, zero-build-tag answer: extract pubsub/kafka, pubsub/google and pubsub/mqtt into their own modules, exactly like pubsub/nats.

separate module build tag
Default build unchanged unchanged
Opt-in go get + wire it remember -tags at every build site
Wrong config compile error at the wiring site runtime ERROR, service starts degraded
CI ordinary go build ./... N-way tag matrix
Coverage gate ordinary tag-only files invisible to the default run
go doc one surface differs per tag
Precedent in this repo 25 0

There is also a distribution problem tags have and modules do not: a tag is set by whoever runs go build, not by the dependency graph. A user building through Docker, ko, goreleaser, Bazel or an inherited Makefile has to thread -tags gofr_nopubsub,gofr_nosqldrivers,gofr_nographql through every one of those. Miss it in a single place and the binary silently reverts to 57 MB, with nothing to indicate it. A module boundary cannot be forgotten.

I do not think that argument is fatal to the whole PR — GraphQL lives in package gofr itself and the SQL drivers are blank imports for database/sql registration, so neither moves to a module easily, and a tag may genuinely be the only option for those two. But those are also the two smallest wins (1.4 MB and 6.1 MB against pub/sub's 8.9 MB). It would be worth splitting the pub/sub half out and asking whether it should be modules instead.


If tags are the agreed mechanism, notes on the implementation

1. The tagged build never exercises the tagged behavior for SQL.

drivers_testdeps_test.go blank-imports lib/pq and modernc.org/sqlite for tests, so under -tags gofr_nosqldrivers the test binary still has both drivers registered. The comment explains why and the reasoning is fair. But the consequence is that the documented behavior —

DB_DIALECT=postgres or =sqlite then fails at startup: NewSQL's registerOtel call reports database/sql's own "unknown driver" error naming the dialect, and returns a nil DB.

— is never tested in any configuration. One test that opens an unregistered dialect directly would cover it without disturbing the rest of the suite.

2. Coverage. Roughly half the added code (*_disabled.go) compiles only under a tag, so the code-climate gate CONTRIBUTING relies on will never see it. The Slim Build Tags job is the right mitigation — worth saying so in the PR description so the coverage delta is not read as a regression by a reviewer who has not spotted the job.

3. enabled() as an interface method. disabledGraphQL.buildSchema() returns nil and GetHandler() returns nil purely because enabled() guards them, which leaves two methods whose contract is "never call me". A const graphQLLinked = false — mirroring pubsubBackendsLinked, which this PR already introduces for pub/sub — would be consistent with the PR's own vocabulary and would let the compiler drop the dead branches outright.

4. The noopResponder relocation rationale is correct and non-obvious (responder.go cannot carry the tag because it holds the exported Responder interface, and leaving noopResponder there makes it unused under the tag and fails the lint gate). Worth keeping that comment exactly as written — it will save someone an afternoon.

5. createMqttPubSub returning an untyped nil in the disabled stub is clean, and composes correctly with #4164, which switches the container's pub/sub guard to isNil. Might be worth cross-linking the two.

Verifying identical go doc -all across 6 packages and an identical linked-package list for the default build is exactly the assertion this class of change needs.

@Umang01-hash Umang01-hash left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Verified end-to-end at the head SHA in a clean worktree: each tag drops its tree completely (graphql→0, sqldrivers→0, pubsub→0 syms), the full set takes a real binary 56.3MB→39.6MB (−16.7MB/~30%), no API break, no typed-nil, fail-loud confirmed by actually running tagged binaries (PUBSUB_BACKEND/DB_DIALECT → ERROR naming the tag, nil datasource, service still boots). Clean, effective work — the interface seams and verbatim moves are well done, and CI building the all-3 combination is the right call.

Requesting changes on disabled-path test coverage + one overstated CI claim — same pattern flagged on #4168, plus two gaps unique here:

  1. The "Default build links the same packages as before" step doesn't assert that — it only compiles + tests. A go list -deps diff (or dep-count check) vs base would make the step earn its name and guard the whole PR's value.
  2. The SQL disabled fail-loud path (unknown-driver → nil DB) has no test, and drivers_testdeps_test.go re-registers pq+sqlite untagged, so CI actively masks the disabled state. GraphQL got a dedicated disabled test; SQL should have parity.
  3. The pubsub disabled fail-loud (pubsubDisabledMsg) is untested — a regression dropping the Errorf (silent no-publish) wouldn't fail CI.

Minor (non-blocking): the graphql_runner.go doc says the tag drops "1.4 MB"; the real measured drop is ~0.83 MB.

Comment thread .github/workflows/go.yml

# The tags are opt-in, so the default build must stay exactly as it was.
# This is the assertion that keeps that true.
- name: Default build links the same packages as before

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This step compiles + tests but never compares the linked-package set to a baseline, so it doesn't assert what its name/comment claim. A go list -deps ./... | sort diff against a committed snapshot (or asserting the graphql/sqldriver/pubsub dep count is unchanged) would make it real — and would catch an accidental default-build regression.

// silent. A user who wants one of these dialects in a tagged build imports
// the driver in their own main package, exactly as with database/sql directly.

package sql

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The fail-loud path this file creates (DB_DIALECT=postgres/sqlite → unknown-driver → nil DB) has no test. drivers_testdeps_test.go blank-imports pq+sqlite untagged, so under -tags gofr_nosqldrivers the test binary re-registers the drivers and the disabled branch is never exercised in CI — the scaffolding masks it. A //go:build gofr_nosqldrivers test asserting NewSQL(...postgres...) returns nil would match the graphql_disabled_test.go treatment.

return nil
}

func (c *Container) createKafkaPubSub(config.Config) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The disabled stubs log fail-loud (pubsubDisabledMsg) but nothing asserts it — container_test.go only adds t.Skip guards. A regression dropping this Errorf (a publisher that silently never publishes) wouldn't fail CI. Worth a tagged test asserting the error is logged and PubSub stays nil, for parity with the graphql disabled path.

… it claims

Review follow-ups on #4167.

The CI step named "Default build links the same packages as before" only ran
go build and go test, so it asserted nothing of the sort. It now diffs
`go list -deps ./... | sort` against the merge base and fails on any change, which
is the claim the tags rest on: 861 packages, identical, measured locally.

The tagged build is also linted now. It was not before, and the first run of the
new step found a real noctx failure in graphql_disabled_test.go that no job would
ever have reported -- the same class of problem that prompted moving noopResponder
and configTrue in the first place.

Two fail-loud paths had no test.

- The disabled pub/sub stubs log an error naming the tag, but container_test.go
  only skips under the tag, and a skip proves nothing about the stub. An edit
  dropping one Errorf would leave every job green while producing the exact
  failure the tag exists to avoid: a publisher that silently never publishes.
  pubsub_backends_disabled_test.go asserts all three, and fails when the Errorf is
  removed.
- registerOtel's "unknown driver" error is what makes a misconfigured tagged build
  legible. It is asserted against a dialect that is registered in NEITHER build,
  not against postgres under the tag: drivers_testdeps_test.go blank-imports pq
  and sqlite so the suite behaves identically either way, which means a tagged
  assertion about postgres would test the fixture rather than the code.

graphQLRunner.enabled() becomes `const graphQLLinked`, matching the
pubsubBackendsLinked the pub/sub side already uses. Whether the engine is linked
is a property of the build, not of an instance, and the compiler can fold the
branch away.

drivers_disabled.go named only postgres and sqlite; supabase and cockroachdb
register under the postgres driver (sql.go:268), so the tag affects them too.

Adds the user-facing documentation the tags had none of, with the numbers
measured rather than asserted (829 packages by default, 617/785/809 per tag, 553
with all three), and a CONTRIBUTING note that these tags are a closed exception
for subsystems already in core -- a new integration ships as its own module.
aryanmehrotra added a commit that referenced this pull request Sep 18, 2026
…rect the grpc claim

Review follow-ups on #4168, plus the #4167 follow-ups merged in.

Each tag was only ever built in isolation, so a symbol that resolves under one
and breaks under two would ship green and fail only for the user who set both.
CI now builds, vets and tests all six together -- verified locally: builds clean,
and 412 packages against the default 829.

The nil-guard on grpcSrv had no test. newGRPCRunner fails on an out-of-range
GRPC_PORT and factory.go logs and continues, so App runs on with no gRPC server,
and these four setters used to dereference the field blind -- a config typo
turning into a nil-pointer panic in the user's own setup code. All four are
asserted, since a later edit is as likely to reintroduce it in one of the others
as in the one that was reported. Neutralising the guard makes the test panic.

The claim that gofr_nootlp "is the tag that actually releases
google.golang.org/grpc" was wrong, and measurably so. Against gofr.dev/pkg/gofr:
gofr_nogrpc alone leaves 82 grpc packages, adding gofr_nootlp leaves 81, adding
gofr_nodgraph still leaves 81, and only adding gofr_nopubsub reaches 0 -- the
Google Pub/Sub client pins grpc through cloud.google.com/go. A shared dependency
goes when its last importer does, which is a property of these tags worth
documenting rather than a detail of this one.

The slim-builds documentation added in #4167 covers all six tags accordingly,
including the table of that measurement, and notes that gofr_nogrpc is the one
tag that changes the API surface.
The tagged lint step ran unscoped, so its first CI run reported every
pre-existing goconst and exhaustive finding in the tree rather than anything this
branch introduced. only-new-issues matches what the code_quality job already
does.

The typos check wants US spelling in the new docs page.
@aryanmehrotra

Copy link
Copy Markdown
Member Author

@PiyushSingh-ZS @Umang01-hash — everything addressed at 4e2121577. All 21 checks green.

Tags vs modules: these three are a closed exception

Agreed that modules are the right pattern, and that's the rule from here on. These three tags are deliberately limited to subsystems already compiled into core, where moving them out breaks existing users:

Tag What a module would break
gofr_nopubsub Kafka/Google/MQTT start from config alone (PUBSUB_BACKEND, container.go:163). Every user adds a go get + an AddPubSub call.
gofr_nosqldrivers DB_DIALECT=postgres/sqlite needs no import today. Users import the driver themselves. Also: the drivers are third-party, so there is no GoFr code to move.
gofr_nographql App.GraphQLQuery/GraphQLMutation are exported methods on App. A module needs a new setup call.

A new integration has no such users, so there is nothing to break — it goes in its own module, which is the existing pattern. I've written that into CONTRIBUTING.md so the tags don't become a precedent, since it was nowhere before.

@Umang01-hash's three threads — all real, all fixed

1. The CI step didn't check what its name claimed. Correct, and it was the worst kind of comment: it asserted the PR's central premise and verified nothing. It now diffs go list -deps ./... | sort against the merge base and fails on any change. Baseline rather than a committed file, so it can't go stale. Verified locally: 861 packages, identical.

2. The unknown-driver path had no test, and your point about the scaffolding masking it is exactly right. That's why the assertion is against a dialect registered in neither build rather than postgres under the tag — drivers_testdeps_test.go blank-imports pq and sqlite so the suite behaves identically either way, which means a tagged assertion about postgres would be testing the fixture, not the code. TestRegisterOtel_UnregisteredDialectFailsLoudly exercises the same otelsql.Registersql.Openunknown driver path in both builds, so it cannot quietly stop running.

3. The disabled pub/sub stubs had no assertion. Also right — skips prove nothing about what the stub does, and a dropped Errorf is precisely the silent-publisher failure the tag exists to avoid. pubsub_backends_disabled_test.go (tagged, so it runs in the Slim job) asserts all three name the client and the tag, and that PubSub stays nil. Removing one Errorf makes it fail.

Also found while fixing those

  • The tagged build was never linted. Added, scoped with only-new-issues — and its first run found a real noctx failure in graphql_disabled_test.go that no job would ever have reported. Same class of problem that prompted moving noopResponder and configTrue.
  • drivers_disabled.go named only postgres and sqlite. supabase and cockroachdb register under the postgres driver (sql.go:268), so the tag affects them too — a supabase user reading the old comment would have been surprised.

@PiyushSingh-ZS's implementation notes

  • enabled()const graphQLLinked, matching pubsubBackendsLinked. Whether the engine is linked is a property of the build, not of an instance, and the compiler folds the branch. The stub keeps buildSchema/GetHandler because untagged gofr.go calls them.
  • Coverage: the tagged files aren't compiled in the default run, so they're unmeasured rather than uncovered — noted in the description, and the Slim job now lints as well as tests them.
  • noopResponder comment kept as-is, agreed.
  • Cross-link to fix(container): stop a typed-nil pub/sub client escaping, and stop isNil panicking #4164 added.

Documentation

There was none for any of these tags — not in the PR, CONTRIBUTING.md or docs/. Added docs/advanced-guide/slim-builds, covering #4168's three tags too, with the numbers measured rather than asserted: 829 packages by default, 617 / 785 / 809 per tag, 553 with all three.

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.

4 participants