Skip to content

Conversation

@NuroDev
Copy link
Contributor

@NuroDev NuroDev commented Jan 13, 2026

Fixes #10400, #9709 and #8475

Currently, if you run wrangler types it only generates TypeScript types for bindings (KVNamespace, D1Database, etc) defined in the top-level configuration (or a single environment when using --env). Now, by default, it collects & generates types for bindings from all environments in your configuration.

This ensures your generated types include all bindings that might be used across different deployment environments (e.g., staging, production), preventing TypeScript errors when accessing environment-specific bindings.

Additionally, If the same binding name exists with different types across environments (e.g., CACHE is a KV namespace in one environment but an R2 bucket in another), an error will be thrown to prevent type conflicts.


A picture of a cute animal (not mandatory, but encouraged)

@NuroDev NuroDev self-assigned this Jan 13, 2026
@changeset-bot
Copy link

changeset-bot bot commented Jan 13, 2026

🦋 Changeset detected

Latest commit: 7a1733a

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

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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 13, 2026

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@11893

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@11893

miniflare

npm i https://pkg.pr.new/miniflare@11893

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@11893

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@11893

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@11893

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@11893

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@11893

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@11893

wrangler

npm i https://pkg.pr.new/wrangler@11893

commit: 7a1733a

);
});

it("should collect vars only from specified environment with --env", async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is something I am not too certain on. Currently main makes it so all variables are union-ized so no matter the environment you have access to all environment variable possibilities.
However, with the change above where using --env makes it so only that specific environments bindings are included, shouldn't vars do the same?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry could you clarify what you mean?

Do we currently get a union of the variables even when --env is specified and your changes here change that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we currently get a union of the variables even when --env is specified and your changes here change that?

Correct. If you were to run this test on main it would generate the following type:

// Without a `--env` flag
interface Env {
    MY_VAR: "top-level" | "staging" | "production";
    STAGING_ONLY: "staging-only-value";
    PROD_ONLY: "prod-only-value";
}

// With a `--env=staging` flag
interface Env {
    MY_VAR: "top-level" | "staging" | "production";
    STAGING_ONLY: "staging-only-value";
    PROD_ONLY: "prod-only-value";
}

But with this PR it generates the following:

// Without a `--env` flag
interface Env {
	MY_VAR: "top-level" | "staging" | "production";
	STAGING_ONLY: "staging-only-value";
	PROD_ONLY: "prod-only-value";
}

// With a `--env=staging` flag
interface Env {
    MY_VAR: "staging";
    STAGING_ONLY: "staging-only-value";
}

So variables are now no longer union-ized when providing an environment. I do feel that if you ask for types for X environment you should get X environments types. But at the same time, I think this would be a breaking change so I am inclined to revert it.

Copy link
Contributor

@vicb vicb left a comment

Choose a reason for hiding this comment

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

Quick first pass, added some comment.

I really like the added comments 🙏

@NuroDev NuroDev marked this pull request as ready for review January 15, 2026 14:30
@NuroDev NuroDev requested a review from a team as a code owner January 15, 2026 14:30
Copy link
Member

@dario-piotrowicz dario-piotrowicz left a comment

Choose a reason for hiding this comment

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

I've left some comments as an initial first review, please have a look 🙂🙏

);
});

it("should collect vars only from specified environment with --env", async () => {
Copy link
Member

Choose a reason for hiding this comment

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

Sorry could you clarify what you mean?

Do we currently get a union of the variables even when --env is specified and your changes here change that?

Comment on lines +1612 to +1617
KV_TOP: KVNamespace;
D1_TOP: D1Database;
KV_STAGING: KVNamespace;
D1_STAGING: D1Database;
KV_PROD: KVNamespace;
R2_PROD: R2Bucket;
Copy link
Member

Choose a reason for hiding this comment

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

if a binding is only present in an environment, could we make it optional?

e.g.

						KV_TOP: KVNamespace;
						D1_TOP: D1Database;
						KV_STAGING?: KVNamespace;
						D1_STAGING?: D1Database;
						KV_PROD?: KVNamespace;
						R2_PROD?: R2Bucket;

I think that that would be more correct and more type-safe 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about this as well and I am still unsure what would be best here. Ideally if you'r binding a resource you should know it always exists and you can access / use it. But on the other hand, in your code how do you know what environment you're in and what resource are or are not available.

Cc @MattieTK

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After a bit of tinkering and seeing what the runtime actually offers us it's a bit more complex.
Because top-level bindings could also not exist (If you run wrangler dev --env staging you of course don't get access to any top-level bindings, only the bindings of that env) we would need to make all top-level bindings optional as well.

Going to have more of a play around with this to try and tweak it.

Copy link
Member

Choose a reason for hiding this comment

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

ah yes, sorry my bad, I forgot that bindings are not inherited from the top-level: https://developers.cloudflare.com/workers/wrangler/configuration/#non-inheritable-keys 👍

Copy link
Member

Choose a reason for hiding this comment

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

So I would suggest that, if possible, if a binding is present in all the environments in the config file (including the top-level) it should be non-nullable, if instead is missing somewhere it should be optional 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

can't generate RPC types when the service binding is targeting a specific environment

4 participants