Quick Start
If you are new to Smithy, the official Smithy quickstart is a good place to familiarize yourself with the IDL before continuing.
Prerequisites
Section titled “Prerequisites”You need the .NET SDK. That’s it for basic builds — NSmithy bundles the Smithy CLI (including a JRE) inside the NuGet package, so no separate Java or Smithy CLI installation is required.
If you enable SmithyGenerateDocs (Sphinx HTML docs), Python 3.11+ must also
be on your PATH.
Optionally install CSharpier for formatted generated code — NSmithy runs it automatically after codegen if available, and silently skips it if not.
Install the NSmithy project templates (one-time):
dotnet new install NSmithy.Templates1. Create the Contracts Project
Section titled “1. Create the Contracts Project”The contracts project owns the Smithy model and distributes it to the server and client.
mkdir HelloWorld && cd HelloWorlddotnet new sln -n HelloWorld# optional: install CSharpier for formatted generated codedotnet new tool-manifestdotnet tool install csharpierdotnet new nsmithy-contracts -n HelloWorld.Contractsdotnet sln add HelloWorld.ContractsThis generates:
HelloWorld.Contracts/ HelloWorld.Contracts.csproj model/ service.smithy ← starter restJson1 HelloService model2. Create the Server
Section titled “2. Create the Server”dotnet new nsmithy-server -n HelloWorld.Server --contracts HelloWorld.Contracts --with-docsdotnet sln add HelloWorld.ServerThe --contracts flag sets the ProjectReference to the contracts project
exactly. --with-docs enables the Smithy docs and OpenAPI endpoints. Build and run:
dotnet run --project HelloWorld.ServerThe server listens on http://localhost:5000. Test it:
curl http://localhost:5000/hello/world# {"message":"Hello, world!"}With --with-docs, two documentation UIs are also available:
/docs— Smithy-generated reference docs for your model/openapi— interactive Scalar UI backed by a generatedopenapi.json
See Endpoint Documentation for details.
3. Create the Client
Section titled “3. Create the Client”dotnet new nsmithy-client -n HelloWorld.Clientdotnet sln add HelloWorld.ClientThe client template defaults to a Maven contracts reference for production use.
For local development, open HelloWorld.Client/HelloWorld.Client.csproj and
replace the SmithyMavenDependency placeholder with a ProjectReference:
<!-- remove this --><SmithyMavenDependency Include="io.github.YOUR_ORG:your-service-contracts:1.0.0" />
<!-- add this instead --><ProjectReference Include="../HelloWorld.Contracts/HelloWorld.Contracts.csproj" />Then run the client with the server still running:
dotnet run --project HelloWorld.Client# Hello, world!When you’re ready to distribute, see Distributing Contracts to publish the contracts JAR and switch back to a Maven reference.
Walking Through the Code
Section titled “Walking Through the Code”The Model
Section titled “The Model”Open HelloWorld.Contracts/model/service.smithy. The template generates a
minimal restJson1 service with a single operation:
@restJson1service HelloService { version: "2006-03-01" operations: [SayHello]}
@readonly@http(method: "GET", uri: "/hello/{name}")operation SayHello { input := { @required @httpLabel name: String } output := { @required message: String }}@restJson1 is the protocol — it controls serialization and HTTP binding
behaviour. @http binds the operation to a route. @httpLabel maps name to
the {name} path segment. This is the source of truth for everything that
follows — change the model, rebuild, and all generated code updates automatically.
Generated Types
Section titled “Generated Types”Running dotnet build invokes the Smithy CLI and generates C# types under
obj/. For the model above you get:
public sealed record SayHelloInput(string Name);public sealed record SayHelloOutput(string Message);And a handler interface the server must implement:
public interface IHelloServiceHandler{ Task<SayHelloOutput> SayHelloAsync( SayHelloInput input, CancellationToken ct = default);}The Server Handler
Section titled “The Server Handler”The generated Program.cs in HelloWorld.Server registers your handler and
maps the routes:
builder.Services.AddHelloServiceHandler<HelloHandler>();
app.MapHelloServiceHttp();HelloHandler (also generated as a starter) simply returns a greeting:
internal sealed class HelloHandler : IHelloServiceHandler{ public Task<SayHelloOutput> SayHelloAsync( SayHelloInput input, CancellationToken cancellationToken = default ) => Task.FromResult(new SayHelloOutput($"Hello, {input.Name}!"));}Replace the body with your real logic. The compiler enforces that every operation in the model has an implementation — add an operation to the model and the build breaks until you handle it.
The Generated Client
Section titled “The Generated Client”HelloWorld.Client/Program.cs uses the generated typed client:
var client = new HelloServiceClient( new HttpClient(), new SmithyClientOptions { Endpoint = new Uri(endpoint) });
var response = await client.SayHelloAsync(new SayHelloInput("world"));Console.WriteLine(response.Message);The client and server share the same generated input/output types from the contracts project. There is no hand-written glue — the model is the contract.
Template Options
Section titled “Template Options”All three templates accept --protocol:
| Value | Protocol |
|---|---|
restJson1 | aws.protocols#restJson1 (default) |
simpleRestJson | alloy#simpleRestJson |
grpc | alloy.proto#grpc (experimental) |
Additional options:
dotnet new nsmithy-server --helpdotnet new nsmithy-contracts --helpdotnet new nsmithy-client --helpExample Repository
Section titled “Example Repository”For a more complete example with multiple operations, error types, and a working client/server setup you can clone and play around with, see nsmithy-minimal.