dotnet new

Create projects, solutions and config files from templates, choose template options deliberately, and ship a team template of your own.

Signature
dotnet new <template> [-n|--name <name>] [-o|--output <dir>] [-f|--framework <tfm>] [--dry-run] [--force] [template options]
  • Added in .NET .NET Core 1.0

Parameters

ParameterTypeDescription
$templatestringShort name of an installed template, for example webapi, web, worker, classlib, xunit, sln, gitignore, globaljson, tool-manifest, buildprops.
$-n, --nameoptionalstring= name of the current folderName of the output: becomes the project file name and root namespace. With no -o, project templates that set preferNameDirectory (webapi, classlib, console) also create a folder of this name; item templates such as sln and gitignore write into the current folder.
$-o, --outputoptionalpath= the current folder, or ./<name> when -n is given to a template with preferNameDirectoryFolder to write into. Created if missing.
$-f, --frameworkoptionalTFM= the SDK's own version (net10.0 on the 10.0 SDK)Target framework written into the project, for example net10.0.
$--dry-runoptionalflag= falsePrints the files that would be created or changed and writes nothing.
$--forceoptionalflag= falseOverwrites existing files. Without it, dotnet new refuses to touch files that already exist.
$--formatoptionalsln | slnx= slnx on the .NET 10 SDKdotnet new sln only: which solution file format to create.

Return value

process exit code0 when the files were created. Non-zero when the template is unknown, an option is invalid, or files would be overwritten without --force.

Errors

Prints an error and returns non-zero for an unknown template or option, and refuses to overwrite existing files unless --force is passed.

Changelog

  • PHP .NET 7Sub-commands became dotnet new install, uninstall, list, search and update; the old --install style switches were deprecated.
  • PHP .NET 9The webapi template no longer references Swashbuckle; it uses Microsoft.AspNetCore.OpenApi and MapOpenApi.
  • PHP .NET 10dotnet new sln creates a .slnx solution file by default.

dotnet new instantiates a template: a folder of files plus a .template.config/template.json that says which tokens to replace and which options exist. The SDK ships the common templates; others come from NuGet template packages installed with dotnet new install. Nothing is compiled or restored; it only writes files.

Names, folders and frameworks

-n Orders.Api sets the project file name and root namespace. For project templates (those with preferNameDirectory, such as webapi, classlib and console) -n without -o also creates a folder of that name; item templates such as sln and gitignore write into the current folder, so dotnet new sln -n Shop creates Shop.slnx right there. -o src/Orders.Api alone takes the name from the folder. Use -o in scripts so the folder layout is explicit. -f defaults to the SDK's own framework, so an SDK picked up from a newer machine can create net11.0 projects in a net10.0 solution; pin the SDK with global.json or pass -f net10.0.

Templates a back-end team uses

Short nameCreatesOptions worth knowing
webapiMinimal API with built-in OpenAPI and an .http file--use-controllers, --auth, --no-https, --no-openapi
webapiaotNative AOT minimal API with source-generated JSONSlim builder, no MVC
webEmpty ASP.NET Core appSmallest starting point
workerGeneric host with a BackgroundServiceNo Kestrel
slnSolution file.slnx on the .NET 10 SDK; --format sln for the old format
gitignore, editorconfig, globaljson, buildprops, tool-manifestRepository filesglobaljson --sdk-version 10.0.402

dotnet new <template> --help lists that template's options, dotnet new list shows what is installed and dotnet new search queries NuGet.org.

Team templates

A company template is a normal project plus template.json. sourceName is the string that is replaced by -n everywhere: file names, namespaces and project references. symbols declare options such as --database, and conditional comments in files (//#if (database == "postgres")) keep or drop code. Pack it with PackageType=Template, publish it to the internal feed and install it with dotnet new install Contoso.Templates::2.3.0. Pin the version so every new service starts from the same baseline.

Failure modes

  • Running dotnet new webapi in the repository root scatters Program.cs and appsettings.json next to the solution. Always pass -o.
  • Re-running a template over an existing project fails; --force overwrites your edited files without a merge. Use --dry-run first.
  • Templates are a snapshot. Fixes in a newer template never reach services created earlier, so shared settings belong in Directory.Build.props, not only in the template.
  • Older build agents and tools that do not read .slnx fail on a new solution; keep them on a current SDK rather than creating .sln files forever.

Example

Example · bash
# A new Orders service in an existing repository, every choice explicit.
cd ~/src/shop

# Pin the SDK first so -f defaults to net10.0 for everyone.
dotnet new globaljson --sdk-version 10.0.402 --roll-forward latestFeature

dotnet new sln -n Shop                              # Shop.slnx on the .NET 10 SDK
dotnet new webapi -o src/Orders.Api --dry-run       # see what would be written
dotnet new webapi -o src/Orders.Api                 # minimal API + OpenAPI + Orders.Api.http
dotnet new classlib -o src/Orders.Domain
dotnet new worker -o src/Orders.Worker              # queue consumer, no HTTP

dotnet new buildprops                               # Directory.Build.props at the root
dotnet new tool-manifest                            # .config/dotnet-tools.json

dotnet sln add src/Orders.Api src/Orders.Domain src/Orders.Worker

# What else is available, and the options of one template
dotnet new list
dotnet new webapi --help

When to use it

  • Scaffold a new Orders.Api and Orders.Worker into src/ of an existing Shop.slnx with explicit -o and a pinned SDK
  • Publish a company template that wires logging, health checks and the internal NuGet feed into every new service
  • Preview with --dry-run what a template would overwrite before re-applying it to an existing repository

Frequently asked questions

Why did dotnet new create a net11.0 project?

-f defaults to the SDK that runs the command, and without global.json that is the newest SDK installed, preview included. Pin the SDK with dotnet new globaljson or pass -f net10.0.

How do I get a classic .sln instead of .slnx?

Run dotnet new sln --format sln. Prefer .slnx with a current SDK and IDE; it is shorter, merges cleanly and is what the .NET 10 SDK creates by default.

Does the webapi template still include Swagger UI?

No. Since .NET 9 it uses Microsoft.AspNetCore.OpenApi and MapOpenApi to serve the document; add a UI such as Scalar yourself if you want one.

More examples

A team template: template.json

Saved as <code>.template.config/template.json</code> next to the project. <code>sourceName</code> is replaced by the value of <code>-n</code> in file names and contents, and <code>preferNameDirectory</code> makes <code>-n</code> create a folder. Users run <code>dotnet new contoso-api -n Orders.Api --database none</code>.

Example · json
{
  "$schema": "http://json.schemastore.org/template",
  "author": "Platform Team",
  "classifications": ["Web", "API"],
  "identity": "Contoso.Templates.OrdersService",
  "name": "Contoso HTTP service",
  "shortName": "contoso-api",
  "sourceName": "Contoso.Service",
  "preferNameDirectory": true,
  "tags": { "language": "C#", "type": "project" },
  "symbols": {
    "database": {
      "type": "parameter",
      "datatype": "choice",
      "choices": [
        { "choice": "postgres", "description": "Npgsql + EF Core" },
        { "choice": "none", "description": "No database" }
      ],
      "defaultValue": "postgres"
    }
  }
}

What dotnet new webapi gives you (Program.cs)

The template's shape with the sample replaced by an orders endpoint. The OpenAPI document is mapped only in Development, and <code>UseHttpsRedirection</code> is on unless <code>--no-https</code> was passed; behind a TLS-terminating proxy it needs forwarded headers to behave.

Example · csharp
var builder = WebApplication.CreateBuilder(args);

// Built-in OpenAPI document (Microsoft.AspNetCore.OpenApi), served at /openapi/v1.json.
builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

app.MapGet("/orders/{id:int}", (int id) =>
        TypedResults.Ok(new OrderSummary(id, "ORD-" + id.ToString("D6"), 129.90m)))
    .WithName("GetOrder");

app.Run();

public sealed record OrderSummary(int Id, string Number, decimal Total);

Packing and installing the template

Installing from a folder is the fast loop while authoring. The <code>::2.3.0</code> suffix pins the package version, so two engineers creating services on the same day get identical files rather than whatever is latest.

Example · bash
# The template pack project has <PackageType>Template</PackageType>
# and includes the template folders as content.
dotnet pack templates/Contoso.Templates.csproj -c Release -o artifacts

# Try it locally from the folder before publishing it.
dotnet new install ./templates/content/OrdersService
dotnet new contoso-api -n Orders.Api -o src/Orders.Api --database postgres

# Everyone else installs a pinned version from the internal feed.
dotnet new install Contoso.Templates::2.3.0
dotnet new uninstall Contoso.Templates

Discussion

  • Be the first to comment on this lesson.