.NET Core
include folder
publish process
deployment
ASP.NET Core

.NET Core include folder in publish

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In .NET, publishing is not the same thing as building. A normal build creates binaries for development, while dotnet publish prepares the files that should actually ship. If you want an extra folder to appear in the published output, you need to mark it as publishable content in the project file.

What dotnet publish Includes by Default

ASP.NET Core projects already publish certain assets automatically, especially files under wwwroot. That is why static files such as CSS, JavaScript, and images usually show up without any extra configuration.

Other folders are not guaranteed to be copied unless the project file tells MSBuild what to do with them. The behavior depends on the item type:

  • 'Compile items are source code files'
  • 'Content items are deployable assets'
  • 'None items exist in the project but are not copied unless you opt in'

If you have a custom folder like Templates, DataFiles, or Scripts, you usually want to treat it as Content.

The Most Common Project File Fix

Use a wildcard in the .csproj file and set CopyToPublishDirectory:

xml
1<Project Sdk="Microsoft.NET.Sdk.Web">
2  <PropertyGroup>
3    <TargetFramework>net8.0</TargetFramework>
4  </PropertyGroup>
5
6  <ItemGroup>
7    <Content Include="Templates\**\*">
8      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
9    </Content>
10  </ItemGroup>
11</Project>

That tells MSBuild to include every file under Templates when publishing. PreserveNewest means files are copied only when needed. If you always want them recopied, use Always.

You can test it with:

bash
dotnet publish -c Release -o ./publish

Then inspect the publish directory and confirm the folder is present.

CopyToOutputDirectory Versus CopyToPublishDirectory

This difference confuses many developers.

CopyToOutputDirectory controls whether files appear in the normal build output, such as bin/Debug/net8.0.

CopyToPublishDirectory controls whether files appear in the publish output.

Sometimes you need both:

xml
1<ItemGroup>
2  <Content Include="SeedData\**\*">
3    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
4    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
5  </Content>
6</ItemGroup>

That is useful when the application needs the files during local runs and in deployment packages.

When wwwroot Is Enough

If the folder contains publicly served static files, placing it under wwwroot is often the cleanest solution:

text
1wwwroot/
2  images/
3  css/
4  downloads/

ASP.NET Core already knows how to serve these files through static file middleware, and publish will include them automatically.

If the folder contains private templates, configuration fragments, seed data, or generated assets that should not be publicly reachable, keep it outside wwwroot and include it explicitly through the project file instead.

A Small Runtime Example

Suppose you publish email templates and read them from disk at runtime:

csharp
1using System.IO;
2
3string basePath = AppContext.BaseDirectory;
4string templatePath = Path.Combine(basePath, "Templates", "welcome-email.txt");
5
6string template = File.ReadAllText(templatePath);
7Console.WriteLine(template);

This code only works after publish if the file was copied into the output. That is why the .csproj change matters.

Choosing Include or Update

Use Include when the files are not already in the project items.

Use Update when the SDK already includes them and you only want to change metadata:

xml
1<ItemGroup>
2  <Content Update="appsettings.Production.json">
3    <CopyToPublishDirectory>Always</CopyToPublishDirectory>
4  </Content>
5</ItemGroup>

That distinction keeps the project file cleaner and avoids duplicate item declarations.

Common Pitfalls

One common mistake is adding CopyToOutputDirectory and assuming publish will behave the same way. Build output and publish output are related, but they are not identical.

Another mistake is putting private runtime files under wwwroot. That makes deployment easy, but it may expose internal assets over HTTP.

A third issue is forgetting wildcards. If you include only the folder name instead of Folder\**\*, MSBuild may not copy the files inside it.

Summary

  • 'dotnet publish only includes files that MSBuild knows should be published.'
  • 'wwwroot is automatically published for static web assets.'
  • Custom folders should usually be marked as Content with CopyToPublishDirectory.
  • 'CopyToOutputDirectory affects build output, while CopyToPublishDirectory affects publish output.'
  • Keep private runtime files outside wwwroot and include them explicitly in the .csproj.

Course illustration
Course illustration