Why public names are only renamed for EXEs

A library's public surface is its contract with callers. This explains the rule, when to enable public renaming, and how to ship a protected library safely.

The Obfuscate public names option applies to .exe files and not to .dll files. That is not an arbitrary limitation — it follows from what a public member actually is.

Visibility is a contract

Private and internal members are invisible outside the assembly. Nothing else can bind to them, so renaming them cannot break anyone. They are always obfuscated.

Public members are the opposite. Marking something public is a statement that other code may depend on it. Renaming a public member is therefore a breaking change to everyone compiled against it.

Why an application is different from a library

An executable is normally the end of the dependency chain. Nothing compiles against your application's public types — the public keyword there is usually habit rather than intent. Renaming those members breaks nobody, so the option is offered and generally worth enabling.

A library exists to be referenced. Its public surface is the product. Rename JsonSerializer.Serialize to a.b and every consumer fails to compile, or fails at runtime with a MissingMethodException if they were already built. So for a DLL the public surface is preserved and everything beneath it is renamed.

This is why the option is EXE-only. It is a safe default that prevents the single most destructive mistake in this space: shipping a library nobody can consume.

What you still get on a library

A common assumption is that preserving the public surface makes obfuscating a library pointless. It does not. In a typical library the public API is a thin layer over substantially more internal code — and that internal code is where the interesting work lives.

A reader of your obfuscated library sees the entry points they were always meant to see, documented in your published API reference anyway. What they no longer get is the readable implementation behind them: your algorithms, your heuristics, your internal data structures. That is the part worth protecting, and it is fully obfuscated.

When an EXE should not have public names renamed

Leave the option off if your executable is loaded or inspected by something else:

  • It hosts a plugin system. Plugins bind to interfaces your EXE exposes; renaming those breaks every plugin.
  • Another assembly references it. Uncommon, but legal — and if a tool or add-in references your EXE, its public surface is a contract.
  • It is a WPF or WinForms application. Test carefully. XAML resolves bindings, commands and event handlers by name at runtime, so public renaming can silently empty your UI. See obfuscation and reflection.
  • It is heavily reflective. Convention-based scanning over your own types stops matching once those types are renamed.

Shipping a protected library properly

If most of your value is in a library and you want it protected without breaking consumers, the durable answer is to shape the assemblies around that goal rather than fight the rename rules.

Split the code. Put the public contract — interfaces, DTOs, the entry-point facade — in a small MyLib.Abstractions assembly and leave it alone. Put the real implementation in MyLib.Core, keep its types internal, and obfuscate it fully. Consumers reference the abstractions and never touch the implementation directly.

Where the implementation must be reachable across assembly boundaries, InternalsVisibleTo lets you keep types internal while still granting access to your own assemblies — you get the protection without making the surface public.

Choosing, in short

You are shippingPublic renaming
A standalone application (console, service, most desktop apps)Enable it
A desktop app with XAML bindingsEnable, then test every view
An application with a plugin APILeave it off
A library consumed by other developersNot applicable — the surface is preserved
A NuGet packageSplit abstractions from implementation

When in doubt, obfuscate both ways and run your smoke tests against each. The cost is a couple of minutes and it settles the question for your specific application far more reliably than a general rule can.

Try it on your own assembly

Upload a DLL or EXE and download the obfuscated result. Free, no signup, nothing stored.