C# Compiler Options that control code generation

The following options control code generation by the compiler. The new MSBuild syntax is shown in Bold. The older csc.exe syntax is shown in code style.

  • DebugType / -debug: Emit (or don't emit) debugging information.
  • Optimize / -optimize: Enable optimizations.
  • Deterministic / -deterministic: Produce byte-for-byte equivalent output from the same input source.
  • ProduceOnlyReferenceAssembly / -refonly: Produce a reference assembly, instead of a full assembly, as the primary output.


The DebugType option causes the compiler to generate debugging information and place it in the output file or files. Debugging information is added by default.


For all compiler versions starting with C# 6.0, there is no difference between pdbonly and full. Choose pdbonly. To change the location of the .pdb file, see PdbFile.

The following values are valid:

Value Meaning
full Emit debugging information to .pdb file using default format for the current platform:
Windows: A Windows pdb file.
Linux/macOS: A Portable PDB file.
pdbonly Same as full. See the note below for more information.
portable Emit debugging information to .pdb file using cross-platform Portable PDB format.
embedded Emit debugging information into the .dll/.exe itself (.pdb file is not produced) using Portable PDB format.


The following information applies only to compilers older than C# 6.0. The value of this element can be either full or pdbonly. The full argument, which is in effect if you don't specify pdbonly, enables attaching a debugger to the running program. Specifying pdbonly allows source code debugging when the program is started in the debugger but will only display assembler when the running program is attached to the debugger. Use this option to create debug builds. If you use Full, be aware that there's some impact on the speed and size of JIT optimized code and a small impact on code quality with full. We recommend pdbonly or no PDB for generating release code. One difference between pdbonly and full is that with full the compiler emits a DebuggableAttribute, which is used to tell the JIT compiler that debug information is available. Therefore, you will get an error if your code contains the DebuggableAttribute set to false if you use full. For more information on how to configure the debug performance of an application, see Making an Image Easier to Debug.


The Optimize option enables or disables optimizations performed by the compiler to make your output file smaller, faster, and more efficient. The Optimize option is enabled by default for a Release build configuration. It is off by default for a Debug and any other build configuration.


You set the Optimize option from Build properties page for your project in Visual Studio.

Optimize also tells the common language runtime to optimize code at run time. By default, optimizations are disabled. Specify Optimize+ to enable optimizations. When building a module to be used by an assembly, use the same Optimize settings as used by the assembly. It's possible to combine the Optimize and Debug options.


Causes the compiler to produce an assembly whose byte-for-byte output is identical across compilations for identical inputs.


By default, compiler output from a given set of inputs is unique, since the compiler adds a timestamp and an MVID (a Module.ModuleVersionId. Basically it is a GUID that uniquely identifies the module and version.) that is generated from random numbers. You use the <Deterministic> option to produce a deterministic assembly, one whose binary content is identical across compilations as long as the input remains the same. In such a build, the timestamp and MVID fields will be replaced with values derived from a hash of all the compilation inputs. The compiler considers the following inputs that affect determinism:

  • The sequence of command-line parameters.
  • The contents of the compiler's .rsp response file.
  • The precise version of the compiler used, and its referenced assemblies.
  • The current directory path.
  • The binary contents of all files explicitly passed to the compiler either directly or indirectly, including:
    • Source files
    • Referenced assemblies
    • Referenced modules
    • Resources
    • The strong name key file
    • @ response files
    • Analyzers
    • Rulesets
    • Other files that may be used by analyzers
  • The current culture (for the language in which diagnostics and exception messages are produced).
  • The default encoding (or the current code page) if the encoding isn't specified.
  • The existence, non-existence, and contents of files on the compiler's search paths (specified, for example, by -lib or -recurse).
  • The Common Language Runtime (CLR) platform on which the compiler is run.
  • The value of %LIBPATH%, which can affect analyzer dependency loading.

Deterministic compilation can be used for establishing whether a binary is compiled from a trusted source. Deterministic output can be useful when the source is publicly available. It can also determine whether build steps that are dependent on changes to binary used in the build process.


The ProduceOnlyReferenceAssembly option indicates that a reference assembly should be output instead of an implementation assembly, as the primary output. The ProduceOnlyReferenceAssembly parameter silently disables outputting PDBs, as reference assemblies cannot be executed.


Reference assemblies are a special type of assembly. Reference assemblies contain only the minimum amount of metadata required to represent the library's public API surface. They include declarations for all members that are significant when referencing an assembly in build tools, but exclude all member implementations and declarations of private members that have no observable impact on their API contract. For more information, see Reference assemblies.

The ProduceOnlyReferenceAssembly and ProduceReferenceAssembly options are mutually exclusive.