Lambda quick start
Create a to-do API, run it locally, then deploy it to AWS and rehearse a rollback. Complete Installation with the .NET 10 SDK first. The local steps need no AWS credentials or Kanject subscription; deployment needs a configured AWS profile. Shell examples use Bash or Zsh.
- Scaffold a service with
kanject newand run it locally withkanject test - Read what the template generated, and where the Kanject CLI files live
- Prepare the
devstage and bind a secret to an environment variable - Deploy with
kanject aws deployand rehearse an alias-flip rollback
1. Scaffold the service
kanject new minimal-api --name Acme.Analytics --framework net10.0 --no-parameter-store --yescd Acme.Analytics/src/Acme.Analytics.Api kanject new runs dotnet new with the template pack bundled in the CLI, then runs kanject init on the Lambda project. You get a to-do API split into Api, Business, Common and Data projects, with integration tests:
Acme.Analytics/├── Acme.Analytics.slnx├── src/│ ├── Acme.Analytics.Api/ ← the Lambda entry: run kanject here│ │ ├── Endpoints/TodoEndpoints.cs│ │ ├── Program.cs│ │ ├── template.json ← the base SAM template deploy builds on│ │ └── kanject-cli/│ │ ├── manifest.json│ │ ├── manifest.lock.json│ │ └── stages/dev.json│ ├── Acme.Analytics.Business/│ ├── Acme.Analytics.Common/│ └── Acme.Analytics.Data/└── tests/ └── Acme.Analytics.Api.Tests/ The kanject-cli/ folder sits inside the API project, so run every kanject command from src/Acme.Analytics.Api. Building it needs the .NET 10 SDK, which minimal-api targets by default; --framework net8.0 targets .NET 8 instead.
2. Run it locally
kanject test --http --watch --env dev --port 5080 Wait for Ready, then request http://localhost:5080/health in a second terminal; expect Healthy. Open http://localhost:5080/ for Swagger UI. Stop the runner with Ctrl+C, then run dotnet test ../../Acme.Analytics.slnx from the API directory.
curl --fail http://localhost:5080/health 3. Read the endpoints
Endpoints are static classes marked [ApiEndpoints]. Kanject.Core.Api.Annotations generates their route registration at compile time, Program.cs maps them all with one call, and each method's XML comments become its OpenAPI description. Each endpoint hands the work to a Business service.
[ApiEndpoints("Todos", "todos", RequireAuthorization = false)]public static class TodoEndpoints{ /// <summary>Lists to-do items, oldest first.</summary> [HttpGet] public static async Task<Ok<IReadOnlyList<Todo>>> ListTodos( bool? done, ITodoService todos, CancellationToken cancellationToken) => TypedResults.Ok(await todos.ListAsync(done, cancellationToken)); /// <summary>Returns one to-do item.</summary> [HttpGet("{id:guid}")] public static async Task<Results<Ok<Todo>, NotFound>> GetTodo( Guid id, ITodoService todos, CancellationToken cancellationToken) => await todos.FindAsync(id, cancellationToken) is { } todo ? TypedResults.Ok(todo) : TypedResults.NotFound(); // CreateTodo, UpdateTodo and DeleteTodo follow the same shape.} 4. Prepare the dev stage
init wrote kanject-cli/stages/dev.json with names derived from the project:
{ "$schema": "../stage.schema.json", "schemaVersion": 1, "region": "eu-west-1", "profile": "default", "stack": "dev-acme-analytics", "artifactBucket": "dev-acme-analytics-artifacts", "env": { "ASPNETCORE_ENVIRONMENT": "Development" }, "entryEnv": {}} Change the region or profile if yours differ. The CLI never creates the artifact bucket, because that is an account decision, so create it once:
aws s3 mb s3://dev-acme-analytics-artifacts --region eu-west-1 --profile default Then check the toolchain and the stage before deploying. Fix anything red first.
kanject doctor --env dev 5. Add a secret (optional)
The public minimal API needs no SSM path or JWT secret. If your own application needs a secret, store one in AWS Secrets Manager and bind it to an environment variable:
kanject add secret ANALYTICS_API_KEY \ acme-analytics/dev/api#key \ --value "$(openssl rand -base64 32)" \ --env dev This creates or updates the secret, stores the value under its JSON key key, and adds ANALYTICS_API_KEY = secret:acme-analytics/dev/api#key to dev.json. Only the reference is committed, never the value. kanject env --env dev shows the binding without fetching the secret.
6. Deploy
kanject aws deploy --env dev# The API's URL is the stack's ApiURL outputaws cloudformation describe-stacks --stack-name dev-acme-analytics \ --query "Stacks[0].Outputs[?OutputKey=='ApiURL'].OutputValue" --output text --region eu-west-1 --profile default deploy resolves every param: and secret: reference, builds and deploys the CloudFormation stack, applies the resolved values to the function, publishes a Lambda version, points the live alias at it, and records the release in the deployment ledger in S3. It finishes by printing the stack and the revision it deployed; the template publishes the API's address as the stack output ApiURL.
7. Rehearse a rollback
A rollback needs something to go back to, so ship a second version first. Then roll back while the stakes are low:
# Change something small, then deploy a second versionkanject aws deploy --env dev# Read the history, then put the first version backkanject aws deployments list --env devkanject aws rollback --env dev --to previous Rollback points the alias back at the earlier version. Nothing is rebuilt, and that version's code and environment come back together.
kanject new minimal-apiscaffolds a to-do API, a.slnxsolution and tests, and runskanject initinside the API project.- Run
kanjectcommands from the API project, wherekanject-cli/lives.kanject test --httpserves the API locally. - The
devstage comes pre-filled; you create its artifact bucket once, andkanject doctor --env devchecks the local configuration. It does not verify bucket access or AWS credentials for this stage. kanject add secretstores a value and commits only its reference.deploypublishes a version and records it in the ledger;rollbackflips the alias back with no rebuild.