Visualstudio-docs: Difference between Directory.Build.props and .targets is not clear

Created on 26 Feb 2019  Â·  7Comments  Â·  Source: MicrosoftDocs/visualstudio-docs

What's the difference between these two files, and which elements should go in which?


Document Details

⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

doc-bug visual-studio-windowprod

Most helpful comment

there might be a lot more to this.

Alas, yes. The problems generally arise because MSBuild is import-order dependent, and the last definition of a property, UsingTask, or target "wins".

MSBuild doesn't care about the extension--with explicit imports, you can import from any extension at any point. But there's a widely-used convention:

  • .props files are imported _early_ in the import order.
  • .targets files are imported _late_ in the build order.

That's _enforced_ by <Project Sdk="Whatever"> imports (the import of Sdk.props comes first, before all of the contents of the file, then Sdk.targets comes last, after all of the contents of the file). But that just formalized the longstanding convention.

Choosing between .props and .targets

So what does this mean for a user who's setting a property? It's impossible to provide _complete_ guidance, because there's a lot of MSBuild logic out there and some of it requires special handling. But I'd offer these guidelines:

  • For many properties, it doesn't matter where they're defined, because they're not overwritten and will be read only at execution time.
  • Set defaults in .props files for behavior that _might be customized in an individual project_.
  • Avoid setting dependent properties in .props files by reading the value of a possibly-customized property, because _the customization won't happen until the user project_.
  • Set dependent properties in .targets files, because they'll pick up customizations from individual projects.
  • If you need to override properties, do it in a .targets file, after all user-project customizations have had a chance to kick in. But be wary of derived properties--they may need to be overridden as well.
  • Include items in .props files (conditioned on a property). _All_ properties are considered before any item, so user-project property customizations will be picked up, and this gives the user project the opportunity to Remove or Update any item brought in by the import.
  • Define targets in .targets files. But remember that this makes overriding the target more difficult if the .targets file is imported by an SDK, because the user project doesn't have a place to override it by default.
  • Prefer customizing properties at evaluation time over changing properties inside a target if possible. This makes it easier to load a project and understand what it's doing.

All 7 comments

I too came to this page hoping to find an answer about what's the difference. But alas that information is not here. Fortunately after a slightly long web search, I came across this blog post from 2010 which states the following:

Typically, imports have the ".props" or ".targets" extension. MSBuild does not really care what the extension is, and considers these to all be just regular MSBuild project files. By convention, the extensions imply that a ".props" file contains property definitions (and/or items and definitions), and a ".targets" file contains target definitions.

So in other words it doesn't really matter.

@AdrianSanguineti it does matter, .props are processed earlier compared to targets. Setting BaseIntermediateOutputPath to change project.assets.json location must be done in props, in targets I got errors.

@MagicAndre1981 I would expect that any property you can include in a .props file could instead go into a .targets file. I believe it would need to be inside of a Target element in the .targets file. @rainersigwald for comment, since there might be a lot more to this.

there might be a lot more to this.

Alas, yes. The problems generally arise because MSBuild is import-order dependent, and the last definition of a property, UsingTask, or target "wins".

MSBuild doesn't care about the extension--with explicit imports, you can import from any extension at any point. But there's a widely-used convention:

  • .props files are imported _early_ in the import order.
  • .targets files are imported _late_ in the build order.

That's _enforced_ by <Project Sdk="Whatever"> imports (the import of Sdk.props comes first, before all of the contents of the file, then Sdk.targets comes last, after all of the contents of the file). But that just formalized the longstanding convention.

Choosing between .props and .targets

So what does this mean for a user who's setting a property? It's impossible to provide _complete_ guidance, because there's a lot of MSBuild logic out there and some of it requires special handling. But I'd offer these guidelines:

  • For many properties, it doesn't matter where they're defined, because they're not overwritten and will be read only at execution time.
  • Set defaults in .props files for behavior that _might be customized in an individual project_.
  • Avoid setting dependent properties in .props files by reading the value of a possibly-customized property, because _the customization won't happen until the user project_.
  • Set dependent properties in .targets files, because they'll pick up customizations from individual projects.
  • If you need to override properties, do it in a .targets file, after all user-project customizations have had a chance to kick in. But be wary of derived properties--they may need to be overridden as well.
  • Include items in .props files (conditioned on a property). _All_ properties are considered before any item, so user-project property customizations will be picked up, and this gives the user project the opportunity to Remove or Update any item brought in by the import.
  • Define targets in .targets files. But remember that this makes overriding the target more difficult if the .targets file is imported by an SDK, because the user project doesn't have a place to override it by default.
  • Prefer customizing properties at evaluation time over changing properties inside a target if possible. This makes it easier to load a project and understand what it's doing.

@rainersigwald, great explanation. The guidelines you've provided was exactly what I was hoping to find back in Feb. Hope that goes into the actual documentation.

@MagicAndre1981, I must agree my statement back in Feb of:

So in other words it doesn't really matter.

is a little misguided and I was doing explicit imports at the time.

I can plan to add this to a section on recommendations/guidance. Sound OK, @rainersigwald ?

Yeah, sounds great.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

realbart picture realbart  Â·  3Comments

jnpwly picture jnpwly  Â·  3Comments

tpodolak picture tpodolak  Â·  3Comments

nitinjs picture nitinjs  Â·  3Comments

wellwind picture wellwind  Â·  3Comments