From dotnet-skills
Using artifacts output layout. UseArtifactsOutput, ArtifactsPath, impact on CI and Docker.
npx claudepluginhub wshaddix/dotnet-skillsThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Reference guide for the .NET SDK artifacts output layout, which centralizes build outputs (bin/, obj/, publish/, package/) into a single artifacts/ directory at the repo root. Available since .NET 8 as an opt-in feature. Recommended for new projects; evaluate tradeoffs before migrating existing projects.
Prerequisites: Run [skill:dotnet-version-detection] first to confirm .NET 8+ SDK -- artifacts output layout is not available in earlier SDK versions.
Scope boundary: [skill:dotnet-project-structure] covers source tree organization (.sln, .csproj, src/, tests/). This skill covers build output organization (artifacts/bin/, artifacts/obj/, artifacts/publish/). Source tree vs output tree.
Cross-references: [skill:dotnet-project-structure] for solution layout, [skill:dotnet-containers] for Dockerfile path adjustments, [skill:dotnet-gha-build-test] for CI artifact upload paths, [skill:dotnet-scaffold-project] for generating new projects with artifacts output enabled.
Traditional .NET build output scatters bin/ and obj/ directories throughout the source tree, one per project. The artifacts output layout consolidates all build outputs under a single artifacts/ directory next to Directory.Build.props.
Benefits:
.gitignore -- one artifacts/ entry replaces per-project bin/ and obj/ entriesbin//obj/ foldersTradeoffs:
bin/Debug/net10.0/ paths must be updatedAdd UseArtifactsOutput to your Directory.Build.props at the repo root:
<Project>
<PropertyGroup>
<UseArtifactsOutput>true</UseArtifactsOutput>
</PropertyGroup>
</Project>
Alternatively, generate a new Directory.Build.props with artifacts output pre-configured:
dotnet new buildprops --use-artifacts
This creates:
<Project>
<PropertyGroup>
<ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath>
</PropertyGroup>
</Project>
Setting ArtifactsPath directly is equivalent to UseArtifactsOutput=true and additionally lets you customize the root directory location.
All build outputs are organized under artifacts/ with three levels: output type, project name, and pivot (configuration/TFM/RID).
artifacts/
bin/
MyApp/
debug/ # Single-targeted project
debug_net10.0/ # Multi-targeted project
release_linux-x64/ # RID-specific build
MyApp.Core/
debug/
obj/
MyApp/
debug/
publish/
MyApp/
release/ # dotnet publish output
release_linux-x64/ # RID-specific publish
package/
release/ # NuGet .nupkg files (no project subfolder)
| Directory | Contents | Traditional equivalent |
|---|---|---|
artifacts/bin/ | Compiled assemblies and dependencies | <project>/bin/ |
artifacts/obj/ | Intermediate build files, generated code | <project>/obj/ |
artifacts/publish/ | Published application output | <project>/bin/<config>/<tfm>/publish/ |
artifacts/package/ | NuGet packages (.nupkg, .snupkg) | <project>/bin/<config>/ |
The pivot subfolder combines configuration, TFM, and RID joined by underscores. Components that are not present are omitted:
| Scenario | Pivot | Full path example |
|---|---|---|
| Single-targeted, debug | debug | artifacts/bin/MyApp/debug/ |
| Multi-targeted, debug | debug_net10.0 | artifacts/bin/MyApp/debug_net10.0/ |
| Release, RID-specific | release_linux-x64 | artifacts/bin/MyApp/release_linux-x64/ |
| Package output | release | artifacts/package/release/ |
Note: artifacts/package/ omits the project name subfolder. The pivot includes only the configuration.
Set ArtifactsPath to change the root location:
<PropertyGroup>
<ArtifactsPath>$(MSBuildThisFileDirectory).output</ArtifactsPath>
</PropertyGroup>
This places all build outputs under .output/ instead of artifacts/.
Customize the pivot subfolder naming with ArtifactsPivots:
<PropertyGroup>
<ArtifactsPivots>$(ArtifactsPivots)_MyCustomPivot</ArtifactsPivots>
</PropertyGroup>
With artifacts output enabled, simplify .gitignore:
# Artifacts output layout (replaces per-project bin/ and obj/ entries)
artifacts/
This single entry replaces the traditional pattern:
# Traditional layout (no longer needed with artifacts output)
[Bb]in/
[Oo]bj/
If using a custom ArtifactsPath, update the .gitignore entry to match.
Multi-stage Dockerfiles that copy build output must reference the new path structure. See [skill:dotnet-containers] for full Dockerfile patterns.
Traditional paths:
COPY --from=build /app/src/MyApp/bin/Release/net10.0/publish/ .
Artifacts output paths:
COPY --from=build /app/artifacts/publish/MyApp/release/ .
Key differences in Dockerfile paths:
artifacts/publish/ not bin/Release/<tfm>/publish/release not Release)CI workflows that upload build artifacts or reference output paths must be updated. See [skill:dotnet-gha-build-test] for full CI workflow patterns.
GitHub Actions -- upload build output:
- name: Publish
run: dotnet publish src/MyApp/MyApp.csproj -c Release
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: app
path: artifacts/publish/MyApp/release/
GitHub Actions -- upload NuGet packages:
- name: Pack
run: dotnet pack -c Release
- name: Upload packages
uses: actions/upload-artifact@v4
with:
name: packages
path: artifacts/package/release/*.nupkg
Azure DevOps -- publish artifacts:
- script: dotnet publish src/MyApp/MyApp.csproj -c Release
displayName: 'Publish'
- task: PublishPipelineArtifact@1
inputs:
targetPath: 'artifacts/publish/MyApp/release/'
artifact: 'app'
When enabling artifacts output on an existing project:
UseArtifactsOutput to Directory.Build.props.gitignore -- replace [Bb]in/ and [Oo]bj/ with artifacts/COPY --from=build paths to use artifacts/ structurebin/ or obj/ pathsbin/ and obj/ directories from all projectsdotnet build and dotnet publish to confirm output appears under artifacts/dotnet test to confirm test execution with new pathsdebug), not debug_net10.0. Multi-targeted projects include the TFM in the pivot.debug, release), not the traditional capitalized names (Debug, Release).artifacts/package/ has a project name subfolder. Unlike bin/, obj/, and publish/, the package/ output type omits the project name level. Packages appear directly under artifacts/package/<config>/.COPY --from=build directives and artifact upload steps that reference traditional bin/ paths.