Why public names are only renamed in applications

A library's public surface is its contract with callers. This explains the rule, when to enable public renaming, and which file to upload for a modern .NET app.

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

Which file do I upload? On .NET Core and later, an application's code lives in MyApp.dll — the MyApp.exe beside it is a native launcher with no managed metadata. Upload the .dll. We identify an application by its entry point rather than its file extension, so public renaming still applies correctly. On .NET Framework the .exe is itself managed, so upload that.

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 applies to applications only. It is a safe default that prevents the single most destructive mistake in this space: shipping a library nobody can consume. Ticking the box on a library is harmless — the setting is simply ignored.

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.