Skip to content

C# API overview

Every public type of the SDK, grouped by what it is for. The guides explain how to use them; this page is for looking things up. Types are in the Inngest namespace unless noted.

Member Purpose
IServiceCollection.AddInngest(Action<InngestOptions>?) Registers the SDK and returns an IInngestBuilder. In Microsoft.Extensions.DependencyInjection.
IServiceCollection.AddInngest(IConfiguration, Action<InngestOptions>?) The same, with settings read from a configuration section such as Inngest in appsettings.json.
IInngestBuilder.AddFunction<TFunction>(FunctionOptions) Registers a class function with these options, resolved from a scope for every call. Attributes on the class are ignored.
IInngestBuilder.AddFunction<TFunction>() Registers a class function configured by its attributes.
IInngestBuilder.AddFunction<TFunction>(Func<FunctionOptions, FunctionOptions>) Registers a class function with the options its attributes give, as the callback changes them.
IInngestBuilder.AddInngestFunctions() Written into your project by the source generator, once the project sets InngestGenerateFunctionRegistration to true: registers every class that has [InngestFunction], as AddFunction<TFunction>() does. See Source generator and analyzers.
IInngestBuilder.AddFunction<TEventData>(FunctionOptions, handler, onFailure?) Registers a delegate function with typed event data.
IInngestBuilder.AddFunction(FunctionOptions, handler, onFailure?) Registers a delegate function with JsonElement event data.
IInngestBuilder.AddMiddleware<TMiddleware>() Registers middleware, one instance per call.
IInngestBuilder.AddMiddleware(InngestMiddleware) Registers one middleware instance for all calls.
IInngestBuilder.AddConnect(Action<ConnectOptions>?) Runs the functions in a Connect worker. Package Inngest.Connect.
IInngestBuilder.AddEntityFrameworkOutbox<TContext>(Action<InngestOutboxOptions>?) Adds the transactional outbox and its hosted dispatcher for a DbContext. Package Inngest.EntityFrameworkCore. See Entity Framework Core outbox.
IEndpointRouteBuilder.MapInngest(string pattern = "/api/inngest") Maps the endpoint Inngest calls. Package Inngest.AspNetCore, namespace Microsoft.AspNetCore.Builder.
IEndpointRouteBuilder.MapInngestRealtime(string pattern, Func<HttpContext, ValueTask<RealtimeSubscription?>> subscription) Serves realtime messages to browsers as server-sent events; the callback returns the RealtimeSubscription(string Channel, IReadOnlyList<string> Topics) a request may receive, or null for 403. Package Inngest.AspNetCore, namespace Microsoft.AspNetCore.Builder. See Realtime.
IHealthChecksBuilder.AddInngest(string? name = null, HealthStatus? failureStatus = null, IEnumerable<string>? tags = null, TimeSpan? timeout = null) Adds a health check that tells a readiness probe whether an app that serves functions can work with Inngest: its keys are configured and Inngest answers a request that carries the signing key. Name "inngest" unless given. Package Inngest.AspNetCore, in Microsoft.Extensions.DependencyInjection. See Health checks.
IHealthChecksBuilder.AddInngest(Action<InngestHealthCheckOptions>, string? name = null, HealthStatus? failureStatus = null, IEnumerable<string>? tags = null, TimeSpan? timeout = null) The same, with the options set by the callback.
IApplicationBuilder.UseInngestDurableEndpoints() Runs the endpoints marked as durable as Inngest runs. Add it after routing. Package Inngest.AspNetCore, namespace Microsoft.AspNetCore.Builder. See Durable endpoints.
IEndpointConventionBuilder.WithDurableEndpoint(DurableEndpointOptions? options = null) Marks an endpoint as durable, so that its handler can take IStepTools and run steps. Also WithDurableEndpoint(string id). Package Inngest.AspNetCore, namespace Microsoft.AspNetCore.Builder.
IServiceCollection.AddInngestRealtimeServerSource() Makes Blazor components read realtime messages from Inngest through IInngestRealtime, on the server. Package Inngest.Blazor. In Microsoft.Extensions.DependencyInjection. See Realtime in Blazor.
IServiceCollection.AddInngestRealtimeRelaySource(Action<RealtimeRelayOptions>) Makes Blazor components read the app’s MapInngestRealtime endpoint over an HttpClient, in WebAssembly. Returns the IHttpClientBuilder of that client. Package Inngest.Blazor. The source registered last, of the two, is the one components get.
IEndpointRouteBuilder.MapInngestWebhook(string pattern, WebhookProvider provider, WebhookOptions? options = null) Maps a POST endpoint that verifies a provider’s webhooks and sends each as an event with the delivery id as its id. Package Inngest.AspNetCore, which brings in Inngest.Webhooks, namespace Microsoft.AspNetCore.Builder. See Webhooks.
IHttpClientBuilder.AddInngestStepFetch() Turns the requests an HttpClient sends from a running function into fetch steps, which Inngest makes. Requests from step handlers and from outside functions go out as usual. Add it last. In Microsoft.Extensions.DependencyInjection.
IInngestBuilder.Services The service collection the SDK is registered in.

AddInngest also registers IInngestClient, IInngestRunsClient and IInngestRealtime, and IStepTools, which resolves to the steps of the durable endpoint or function that is running.

InngestOptions: AppId, AppVersion, EventKey, SigningKey, SigningKeyFallback, Environment, IsDev, DevServerUrl, BaseUrl, ApiBaseUrl, EventApiBaseUrl, ServeOrigin, ServePath, AllowInBandSync, AllowUnsignedSync, Streaming, SessionPropagation, Checkpointing, SerializerOptions. See Configuration.

ConnectOptions: InstanceId, MaxWorkerConcurrency, GatewayUrl. See Connect.

InngestHealthCheckOptions: RequireEventKey, CheckSync, CacheDuration (30 seconds) and FailureCacheDuration (5 seconds). See Health checks.

FunctionOptions, an immutable record:

Property Type
Id (required) string
Name string?
Triggers (required) IReadOnlyList<FunctionTrigger>
Retries int?
Concurrency IReadOnlyList<ConcurrencyLimit>?
Throttle, RateLimit, Debounce, BatchEvents, Priority records of the same names
Idempotency string?
CancelOn IReadOnlyList<CancelOn>?
Timeouts FunctionTimeouts?
Singleton Singleton?
Middleware IReadOnlyList<FunctionMiddleware>?; see Middleware
Checkpointing CheckpointingOptions?

The flow control records and their constructor arguments and properties:

Record Constructor Properties
ConcurrencyLimit (int Limit); 0 means no limit Key, Scope (ConcurrencyScope.Function, Environment, Account)
Throttle (int Limit, TimeSpan Period) Burst, Key
RateLimit (int Limit, TimeSpan Period) Key
Debounce (TimeSpan Period) Key, Timeout
BatchEvents (int MaxSize, TimeSpan Timeout) Key, If
Priority (string Run)
CancelOn (string Event) If, Match, Timeout
FunctionTimeouts Start, Finish
Singleton (SingletonMode Mode) Key; modes Skip and Cancel

Triggers: Trigger.Event(string name, string? @if = null) and Trigger.Event<T>(string? @if = null), for a typed event T, return an EventTrigger. Trigger.Cron(string schedule, string? timezone = null) and Trigger.Cron(string schedule, TimeSpan jitter, string? timezone = null) return a CronTrigger, whose Jitter, from 1 second to 5 minutes, starts each scheduled run up to that much later. EventTrigger and CronTrigger derive from FunctionTrigger. CancelOn.For<T>() returns a CancelOn for a typed event.

CheckpointingOptions, a record. Checkpointing runs the steps of a function one after another in the same call from Inngest and saves each to Inngest as it completes, instead of ending the call after every step. It is off by default. InngestOptions.Checkpointing sets it for every function, and FunctionOptions.Checkpointing, which wins over it, for one function.

Property Default Meaning
Enabled true false turns checkpointing off for one function when the app turns it on.
MaxRuntime null: 10 seconds for the serve endpoint, 5 minutes for Connect workers How long one call may keep running steps. Timeout.InfiniteTimeSpan removes the limit.
BufferedSteps 1 How many completed steps are saved to Inngest together.
MaxInterval null The longest a completed step waits to be saved while BufferedSteps is not reached; null waits until the buffer is full or the call ends.

Each sets the FunctionOptions member of the same name; durations are time strings such as "30s" or "1h30m". AddFunction<TFunction>() reads them when the app starts: it starts from [InngestFunction] and applies the others, which derive from FunctionOptionsAttribute, in ascending Order, then in the order they are declared.

Attribute Constructor Properties
InngestFunctionAttribute (string id) Name, Retries, Idempotency
EventTriggerAttribute, EventTriggerAttribute<T> (string name), () If; repeatable
CronTriggerAttribute (string schedule) Timezone, Jitter; repeatable
ConcurrencyAttribute (int limit) Key, Scope; repeatable
ThrottleAttribute (int limit, string period) Burst, Key
RateLimitAttribute (int limit, string period) Key
DebounceAttribute (string period) Key, Timeout
BatchEventsAttribute (int maxSize, string timeout) Key, If
PriorityAttribute (string run)
SingletonAttribute (SingletonMode mode) Key
CancelOnAttribute, CancelOnAttribute<T> (string name), () If, Match, Timeout; repeatable
TimeoutsAttribute Start, Finish
FunctionOptionsAttribute Order; Apply(FunctionOptions) returns the options with the attribute applied. Derive from it and override Configure(FunctionOptions) for an attribute of your own.

The generic forms take the event’s name from T, which implements IInngestEventData.

Type Purpose
InngestFunction<TEventData> Base class of class functions. Override ExecuteAsync(FunctionContext<TEventData>, CancellationToken), which returns Task<object?>.
InngestFunction<TEventData, TResult> Base class of class functions with a result type: ExecuteAsync returns Task<TResult>. InngestFunction<TEventData> derives from it with object?.
InngestFunction The base of both, which the methods that take a function class require. A class cannot derive from it directly.
IReturns<TResult> Implemented by InngestFunction<TEventData, TResult>, so that InvokeAsync<TFunction, TResult> can require the result type.
FunctionContext What every call has: FunctionId, RunId, Attempt, MaxAttempts, Step, Logger, Services, CancellationToken, RequestId, JobId and Sessions, the run’s sessions that what it sends inherits. For code that does not know the event type, such as middleware: EventName, EventId and RawEvent, the triggering event as JSON.
FunctionContext<TEventData> Adds Event and Events.
IFailureHandler Implement OnFailureAsync(FunctionContext<FunctionFailure>, CancellationToken) to handle final failures.
FunctionFailure The failure handler’s event data: FunctionId, RunId, Error, Event.
FunctionError A failure as Inngest stores it: Name, Message, Stack, and Cause, the error that caused it.
SystemEvents The names of the events Inngest sends about runs: FunctionFailed, FunctionFinished, FunctionCancelled, FunctionInvoked, ScheduledTimer.
FunctionFinished The data of inngest/function.finished, sent when a run ends however it ends: FunctionId, RunId, Result, Error, Event, CorrelationId.
FunctionCancelled The data of inngest/function.cancelled: FunctionId, RunId, Event, CorrelationId.

IStepTools, the type of context.Step:

Method Returns
RunAsync<T>(string id, Func<CancellationToken, Task<T>> handler) Task<T>
SleepAsync(string id, TimeSpan duration) Task
SleepUntilAsync(string id, DateTimeOffset until) Task
WaitForEventAsync<TData>(string id, WaitForEventOptions options) Task<InngestEvent<TData>?>
InvokeAsync<TResult>(string id, InvokeOptions options) Task<TResult>
SendEventAsync(string id, IReadOnlyList<InngestEvent> events) Task<SendEventsResult>
InvokeAsync<TFunction, TResult>(string id, object? data = null, TimeSpan? timeout = null) Task<TResult>; runs the function registered as TFunction, which must return a TResult
WaitForSignalAsync<TData>(string id, WaitForSignalOptions options) Task<InngestSignal<TData>?>; null when the timeout passes first
SendSignalAsync(string id, InngestSignal signal) Task<string?>: the id of the run the signal resumed, or null when no run waits for it
FetchAsync(string id, HttpRequestMessage request) Task<HttpResponseMessage>; Inngest makes the request, and the response is memoized
InferAsync<TResponse>(string id, InferOptions options) Task<TResponse>; Inngest sends the request to the AI provider, and the response is memoized
AIWrapAsync<TInput, TResult>(string id, TInput input, Func<TInput, CancellationToken, Task<TResult>> handler) Task<TResult>; runs your own model call like a run step that the Inngest UI shows as one, with the input; a rerun with an input edited there passes the edited input
RunScopedAsync<T>(string id, Func<IServiceProvider, CancellationToken, Task<T>> handler) Task<T>; runs the handler once like a run step, in a dependency injection scope of its own that is created when the handler starts and disposed when it ends. See Scoped steps
PublishAsync<T>(string id, RealtimeTopic topic, T data) Task<T>; publishes a realtime message once, tagged with the run; also for a RealtimeTopic<T>
PublishStreamAsync(string id, RealtimeTopic topic, IAsyncEnumerable<string> chunks) Task<string>; streams the text to the topic as it arrives and memoizes all of it, so a replay does not read the chunks again
ParallelAsync<T>(ParallelMode mode, Func<Task<T>> steps) Task<T>; runs the callback with the mode applied to every step it creates

The members after the first six have default implementations, so a fake only has to implement the six. The defaults of InvokeAsync<TFunction, TResult>, WaitForSignalAsync, SendSignalAsync, FetchAsync, InferAsync, AIWrapAsync, RunScopedAsync, PublishAsync and PublishStreamAsync throw NotSupportedException. Every method but ParallelAsync also has an overload that takes a StepOptions in place of the id.

StepToolsExtensions adds RunAsync overloads for handlers that take no token, return no value or are synchronous, a non-generic WaitForEventAsync that returns JsonElement data, and SendEventAsync for a single event. For a typed event T it adds WaitForEventAsync<T>(string id, TimeSpan timeout, string? match = null, string? @if = null) and SendEventAsync<T> for one T or several. It also adds a non-generic WaitForSignalAsync with JsonElement data, an InferAsync that returns JsonElement, an AIWrapAsync whose handler takes no token, and ParallelAsync(ParallelMode, Func<Task>) for steps without a result. For scoped steps it adds a RunScopedAsync whose handler returns no result, and RunScopedAsync<TService, T> and RunScopedAsync<TService>, whose handler takes the TService that the SDK resolves from the step’s scope with GetRequiredService. These methods also take a StepOptions in place of the id, except ParallelAsync.

Record Constructor Properties
StepOptions (string Id) Name, shown in the Inngest UI; ParallelMode, for this step instead of the mode of an enclosing ParallelAsync. A string converts to it implicitly.
WaitForEventOptions (string Event, TimeSpan Timeout) Match, If
InvokeOptions (string FunctionId) AppId, Data, User, Timeout, Meta, the sessions of the invoked run
WaitForSignalOptions (string Signal, TimeSpan Timeout) OnConflict: SignalConflict.Fail, the default, fails the run when another run already waits for the signal; Replace takes the signal over
InngestSignal (string Name, object? Data = null) A signal to send.
InngestSignal<TData> (string Name, TData Data) A signal as the waiting run receives it.
InferOptions (AIFormat Format, Uri Url, object Body) AuthKey, Headers

ParallelMode is Wait, the default, where Inngest calls the function again once all the steps started together have finished, or Race, where it calls the function again each time one of them finishes. See Parallel steps. AIFormat names the provider API: OpenAIChat, OpenAIResponses, Anthropic, Gemini, Grok or AzureOpenAI.

FanOutExtensions adds methods to IStepTools that run a step for each item of an IReadOnlyList<TItem>, with the id id[index], and return the results, as arrays like Task.WhenAll, in the order of the items. They need nothing from the engine’s public surface, so they also work on a fake of IStepTools. Each takes FanOutOptions? options = null and CancellationToken cancellationToken = default after the arguments listed here. See Fan-out over a list.

Method Returns
MapAsync<TItem, TResult>(string id, IReadOnlyList<TItem> items, Func<TItem, CancellationToken, Task<TResult>> handler) Task<TResult[]>; the first item that fails for good stops the list, and its StepFailedException is thrown
ForEachAsync<TItem>(string id, IReadOnlyList<TItem> items, Func<TItem, CancellationToken, Task> handler) Task; the same for a handler without a result
MapOutcomesAsync<TItem, TResult>(string id, IReadOnlyList<TItem> items, Func<TItem, CancellationToken, Task<TResult>> handler) Task<FanOutOutcome<TResult>[]>; every item runs, and each has an outcome
MapInChunksAsync<TFunction, TItem, TResult>(string id, IReadOnlyList<TItem> items, int chunkSize) Task<TResult[]>; each chunk of chunkSize items runs in a run of the FanOutFunction<TItem, TResult> class TFunction, with the id id[first-last]
MapOutcomesInChunksAsync<TFunction, TItem, TResult>(string id, IReadOnlyList<TItem> items, int chunkSize) Task<FanOutOutcome<TResult>[]>

Inngest fails a run once 1,000 of its steps have completed, and every step of the run counts. So the methods without chunks refuse a list of 1,000 items or more, and the chunked methods a chunkSize of 1,000 or more and a list that makes 1,000 chunks or more, with a NonRetriableException, which is not retried. Fewer fit when the function has other steps.

Type Members
FanOutOptions, a record MaxParallelism: how many items, or chunks, run at once, all of them by default. ParallelMode: Wait, Race, or null for the mode of the enclosing ParallelAsync. ChunkTimeout: how long a chunk’s run may take.
FanOutOutcome<TResult>, a record struct Index, Value, Error (a FunctionError?) and Succeeded
FanOutFunction<TItem, TResult>, an abstract class The function of a chunk. Implement ProcessAsync(TItem item, CancellationToken cancellationToken); override MaxParallelism, the number of items of a chunk that run at once. Register it with AddFunction<T>(), with no trigger.
FanOutChunk<TItem>, a record (int Offset, IReadOnlyList<TItem> Items, bool FailFast): the event data of a chunk’s run. A source-generated JsonSerializerContext needs it, and FanOutOutcome<TResult>[], the output of the run.
Type Purpose
IInngestClient SendAsync for one InngestEvent or several, each also with a SendOptions; SendSignalAsync(InngestSignal, CancellationToken), also with a SendOptions, which returns the id of the run the signal resumed, or null when no run waits for it; AppId.
IInngestEventData Implemented by an event’s data record: static abstract string EventName and static virtual string? EventVersion.
InngestClientExtensions SendAsync<T>(T, CancellationToken) and SendAsync<T>(IEnumerable<T>, CancellationToken) for typed events.
InngestEvent An event to send: (string Name, object? Data = null) with Id, User, Timestamp, Version, Meta.
InngestEvent<TData> A received event: Name, Data, Id, User, Timestamp, Version, Meta.
EventMeta An event’s sessions: Sessions, its own, where a null id drops an inherited session; PropagatedSessions, those it inherits from the run that sends it, which the SDK fills in; InheritSessions, false to inherit none. See Sending events.
SendEventsResult Ids of the sent events, in order.
SendOptions Options for one send: Environment, a branch environment to send to instead of the app’s.

IInngestRunsClient reads and cancels runs through the Inngest REST API, with the app’s signing key:

Method Returns
GetRunAsync(string runId, CancellationToken) Task<FunctionRun>: the run’s status and, once it has ended, its output
GetEventRunsAsync(string eventId, CancellationToken) Task<IReadOnlyList<FunctionRun>>: the runs an event started, by the event id that sending it returned
CancelRunAsync(string runId, CancellationToken) Task; a step that is running finishes, and no further steps run

FunctionRun, a record: RunId, Status, FunctionId (Inngest’s own id of the function, a UUID), FunctionVersion, StartedAt, EndedAt, EventId, BatchId, OriginalRunId, Cron, EnvironmentId, Output and GetOutput<T>(), which reads the output with the app’s serializer options. Status is a FunctionRunStatus: Unknown, Scheduled, Running, Completed, Failed or Cancelled.

Inngest caches these answers for a few seconds, a run for 3 and the runs of an event for 15, and only EndedAt says for sure that a run is over. Failures throw InngestException with Inngest’s message.

IInngestRealtime publishes, streams and receives realtime messages and mints subscription tokens through the Inngest API, with the app’s signing key. See Realtime.

Method Returns
PublishAsync<T>(RealtimeTopic topic, T data, CancellationToken) Task; publishes at once, tagged with the run when called inside one. Text goes out as it is, anything else as JSON. Also for a RealtimeTopic<T>.
PublishStreamAsync(RealtimeTopic topic, IAsyncEnumerable<string> chunks, CancellationToken) Task<string>: all the text, streamed to the topic in one request as it arrives
SubscribeAsync<T>(RealtimeTopic<T> topic, CancellationToken) IAsyncEnumerable<RealtimeMessage<T>>: the topic’s messages from now on, with the data read as a T
SubscribeAsync(string channel, IReadOnlyList<string> topics, CancellationToken) IAsyncEnumerable<RealtimeMessage<JsonElement>> for several topics of a channel
GetSubscriptionTokenAsync(string channel, IReadOnlyList<string> topics, CancellationToken) Task<RealtimeToken> for a browser to subscribe to these topics of the channel

RealtimeTopic, a record (string Channel, string Name), and RealtimeTopic<T>, the same for data of type T, with Untyped for the members that take any topic. RealtimeMessage<T>, a record (RealtimeMessageKind Kind, string Channel, string Topic) with Data, StreamId, Text, RunId and CreatedAt; RealtimeMessageKind is Data, StreamStart, StreamChunk, StreamEnd, Run or Other. RealtimeToken, a record (string Channel, IReadOnlyList<string> Topics, string Key) with ApiBaseUrl; serialized with camelCase names, it is the token object that useRealtime and subscribe of the TypeScript SDK take.

Package Inngest.AspNetCore. The API is marked [Experimental("INNGEST001")], because Inngest calls durable endpoints beta; Durable endpoints shows how to suppress the diagnostic.

DurableEndpointOptions, the argument of WithDurableEndpoint:

Property Type Default
Id string? The method and the route pattern, such as POST /orders/{id}
Retries int? 3
AsyncResponse DurableEndpointResponse Redirect
RedirectUrl Func<DurableEndpointRun, Uri>? The output URL on the Inngest API
MaxRequestBodySize int 1 MiB; a larger request gets 413

DurableEndpointResponse is what the client gets when Inngest takes the run over: Redirect, a 303 to the URL that answers with the endpoint’s response, or Token, a 200 with {"run_id", "token"}. DurableEndpointRun, a record (string RunId, string Token), is what RedirectUrl receives.

DurableEndpointAttribute marks a controller or an action, as WithDurableEndpoint does for a minimal API endpoint. Its constructor is (string? id = null), and its properties are Retries, where a negative number means the default, and AsyncResponse. DurableEndpointDiagnostics.Id is "INNGEST001", the diagnostic that marks the API.

Exception Meaning
NonRetriableException Thrown by your code to fail a step or run without retrying.
RetryAfterException Thrown by your code to retry after Delay or at RetryAt.
StepFailedException Thrown by the SDK where a step that failed for good is awaited: StepId, Error. When the recorded error has a cause, InnerException is a FunctionErrorException for it.
FunctionErrorException An error Inngest recorded, rebuilt as an exception: Error holds the recorded name, message and stack, and InnerException the recorded cause.
InngestException Thrown by the SDK when talking to Inngest fails, with StatusCode when there is one.

InngestMiddleware has virtual hooks that do nothing by default: OnRunStartAsync, OnMemoizationEndAsync, OnRunCompleteAsync, OnRunErrorAsync, OnStepStartAsync, OnStepCompleteAsync, OnStepErrorAsync, WrapFunctionAsync, WrapStepAsync, WrapStepHandlerAsync and WrapSendEventAsync. StepInfo describes a step: Id, HashedId, Type, Memoized, and Name, the display name the code gave it. Type is a StepType: Run, Sleep, WaitForEvent, Invoke, SendEvent, WaitForSignal, SendSignal, Fetch, AIInfer, AIWrap or RealtimePublish. See Middleware.

FunctionMiddleware is middleware for one function, listed in FunctionOptions.Middleware. It runs inside the app’s middleware, also for the function’s failure handler. FunctionMiddleware.Of<TMiddleware>() resolves TMiddleware from the call’s scope and registers it as scoped unless the app registered it; FunctionMiddleware.Of(Func<IServiceProvider, InngestMiddleware>) calls the factory with the call’s scope on every call.

IPayloadTransform, implemented by a middleware, rewrites the raw JSON between Inngest and the function:

Method Rewrites
TransformEvent(JsonElement @event, Utf8JsonWriter writer) A triggering event, before the function’s event type is read from it
TransformStepResult(FunctionContext context, StepInfo step, JsonElement result, Utf8JsonWriter writer) A memoized result of any step type, before the step’s result type is read from it
TransformStepOutput(FunctionContext context, StepInfo step, JsonElement output, Utf8JsonWriter writer) What a step handler returned, before Inngest memoizes it
TransformFunctionOutput(FunctionContext context, JsonElement output, Utf8JsonWriter writer) The function’s output, before it is sent to Inngest

Each method writes one replacement value and returns true, or writes nothing and returns false to keep the value; the defaults keep every value. JSON coming in reaches the transforms in registration order, and JSON going out in reverse order.

Package Inngest.Connect. AddConnect registers IInngestConnection, the worker’s connection to Inngest: State, and WaitForStateChangedAsync(InngestConnectionState lastObservedState, CancellationToken), which completes with the state the connection moves to. InngestConnectionState is Connecting, Active, Reconnecting, Closing or Closed.

IHealthChecksBuilder.AddInngestConnect(string name = "inngest-connect", HealthStatus? failureStatus = null, IEnumerable<string>? tags = null), in Microsoft.Extensions.DependencyInjection, adds a health check that is healthy only while the connection is Active. See Deploying.

Package Inngest.Aspire.Hosting, for the AppHost project. The resource type is in Aspire.Hosting.ApplicationModel and the extension methods, on IDistributedApplicationBuilder and IResourceBuilder<T>, are in Aspire.Hosting, the namespaces an AppHost imports. See Aspire.

Member Purpose
AddInngest(string name, int? port = null, int? connectPort = null) Adds the dev server as a container running inngest dev --no-discovery, with health checks on /health and on the gateway’s /ready and its UI linked in the dashboard. port and connectPort fix the host ports of the API and the gateway. The dev server is left out of a manifest. Returns an IResourceBuilder<InngestServerResource>.
AddInngestSelfHosted(string name, IResourceBuilder<ParameterResource>? signingKey = null, IResourceBuilder<ParameterResource>? eventKey = null, int? port = null, int? connectPort = null) Adds a self-hosted server, inngest start, that signs its requests and wants an event key. Keys that are not given are generated and kept in the user secrets of the AppHost. A key that inngest start would refuse is reported when the server starts. The server is part of a manifest, with the keys as parameters.
IResourceBuilder<InngestServerResource>.WithApp<TApp>(IResourceBuilder<TApp> app, string path = "/api/inngest", string endpointName = "http") Makes the server sync an app that serves functions, at the address its container reaches the endpoint on. Call it once for every app.
IResourceBuilder<TDestination>.WithReference(IResourceBuilder<InngestServerResource> inngest) Gives a project or container INNGEST_DEV (the dev server) or INNGEST_DEV=0, INNGEST_SIGNING_KEY and INNGEST_EVENT_KEY (the self-hosted server), and for both INNGEST_BASE_URL, INNGEST_API_BASE_URL and INNGEST_EVENT_API_BASE_URL with the server’s address, and INNGEST_CONNECT_GATEWAY_URL for workers. In a manifest a reference to the dev server adds nothing.

InngestServerResource, a ContainerResource: IsSelfHosted; SigningKeyParameter and EventKeyParameter, which are null for the dev server; PrimaryEndpoint, the endpoint named http that serves the REST API, the event API and the UI; and ConnectEndpoint, the endpoint named connect that is the gateway of Connect workers. Its constructor takes the name and, for a self-hosted server, both keys.

Package Inngest.AwsLambda. See Running on AWS Lambda.

Member Purpose
InngestLambdaHandler(IServiceProvider services) Takes the SDK from the service provider of an app that called AddInngest, and fails at once when it did not. Build one when the function starts.
HandleAsync(APIGatewayProxyRequest request, ILambdaContext context) Serves an event of an API Gateway REST API (payload format 1.0) and returns an APIGatewayProxyResponse.
HandleAsync(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) Serves an event of an API Gateway HTTP API or a Lambda function URL (payload format 2.0) and returns an APIGatewayHttpApiV2ProxyResponse.

Each invocation runs in a service scope of its own. The cancellation token that functions receive is never cancelled, and InngestOptions.Streaming has no effect, since the response is buffered; building the handler logs a warning when it is on. The event types are those of Amazon.Lambda.APIGatewayEvents, and the package ships no JsonSerializerContext for them.

Package Inngest.AzureFunctions.

Member Purpose
HttpRequestData.ServeInngestAsync() Serves the Inngest endpoint from an HTTP-triggered function of the isolated worker: GET answers introspection, PUT syncs the app and POST runs functions. Returns the HttpResponseData the function returns. It works with the built-in HTTP model and with the ASP.NET Core integration, where InngestOptions.Streaming streams a long call. Requires services.AddInngest(). In Microsoft.Azure.Functions.Worker.Http.

The function that calls it is declared in the app. See Azure Functions.

Package Inngest.OpenTelemetry.

Member Purpose
IInngestBuilder.AddInstrumentation() Adds the middleware that traces and measures runs. Add it before other middleware, so that their work falls inside its spans.
TracerProviderBuilder.AddInngestInstrumentation() Collects the SDK’s spans. In OpenTelemetry.Trace.
MeterProviderBuilder.AddInngestInstrumentation() Collects the SDK’s metrics. In OpenTelemetry.Metrics.
InngestInstrumentation.ActivitySourceName, InngestInstrumentation.MeterName "inngest", for AddSource, AddMeter or a listener of your own.

The spans are inngest.execution, one per call from Inngest, and inngest.step, one per step the app executes; a Connect worker adds inngest.connect.request for every request it receives. The metrics are inngest.run.started, inngest.run.completed, inngest.run.failed, inngest.retries, inngest.execution.duration and inngest.step.duration, with durations in seconds. The tracing middleware example shows how to write such a middleware yourself.

Package Inngest.Encryption. See Encryption.

Member Purpose
IInngestBuilder.AddEncryption(Action<EncryptionOptions>?) Adds the middleware that encrypts event data, step results and function output and decrypts what comes back, in the format of @inngest/middleware-encryption. Register it after middleware that add or change events.

EncryptionOptions:

Member Purpose
Key The key that encrypts, and the first one tried when decrypting. Required unless Service is set.
FallbackDecryptionKeys Keys that only decrypt, for replacing a key. Empty by default.
DecryptOnly Reads encrypted data and writes none. false by default.
EventEncryptionField The top-level field of an event’s data that is encrypted when the event is sent. "encrypted" by default.
Service An EncryptionService that encrypts in place of the default strategy.

EncryptionService, an abstract class: Identifier, which the envelope’s __STRATEGY__ carries; Encrypt(ReadOnlySpan<byte> json), which returns the text of the data field; and Decrypt(string data), which returns the UTF-8 JSON of the value.

Package Inngest.Sentry.

Member Purpose
IInngestBuilder.AddSentryReporting(Action<SentryReportingOptions>?) Adds the middleware that reports the errors of functions and steps to Sentry. Add it before other middleware, so that their work falls inside its scope.

SentryReportingOptions: OnlyCaptureFinalAttempt (default true), CaptureStepErrors (false), DisableAutomaticFlush (false) and FlushTimeout (2 seconds). See Middleware for the tags, the trace and the options.

Package Inngest.Extensions.AI. The extension methods are in Microsoft.Extensions.AI. See AI chat clients.

Member Purpose
ChatClientBuilder.UseInngestSteps(Action<InngestStepsOptions>?) Makes each call to the model inside a run a step: the messages and options are its input, the ChatResponse as JSON its result, and a replay returns the saved response without calling the model. A streaming call runs the whole stream in its step. Outside a run, and inside a step handler, calls pass through.
ChatClientBuilder.UseInngestFunctionInvocation(Action<FunctionInvokingChatClient>?, Action<InngestStepsOptions>?) Adds a FunctionInvokingChatClient, as UseFunctionInvocation does, whose invocations of tools inside a run are steps named tool <name>, with the arguments as input and {"result": ...} saved. A tool that throws is retried like any step, except for an ArgumentException, which fails its step at once.
ChatOptions.WithInngestStepId(string) Names the step of one call, in place of chat, for calls that reach the client in no fixed order, such as ones made after a request that finishes at varying times. The steps of its tools carry the name. The client removes the name before the options reach the model.
ChatOptions.WithInngestRealtimeStream(RealtimeTopic) Publishes the text of a streaming call to the topic while the model produces it, gathered into chunks of up to 1 KB, at most 1,000 to a stream. Failing to publish does not fail the call.

InngestInferChatClient(Uri endpoint, string model, string? apiKey = null, IReadOnlyDictionary<string, string>? headers = null), in the Inngest namespace, is an IChatClient whose calls are inference steps in the OpenAI chat completions format: Inngest makes the request, and no worker waits for it. It works inside a run only, sends max_completion_tokens, and fails for good on an answer that is an error or has no choices. A strict additional property of the options, or of a function, asks for strict structured outputs.

InngestStepsOptions, in the Inngest namespace: RecordInput (default true) records the messages and options of a model call, or the arguments of a tool call, as the input of its step; without it the step is a plain run step.

Part of the Inngest package, which carries them in analyzers/dotnet/cs for the compiler to load. See Source generator and analyzers.

Member Purpose
IInngestBuilder.AddInngestFunctions() An extension method that the generator writes into each project that has turned generation on and has function classes, in the namespace Inngest, in a static class named after the assembly. It calls AddFunction<T>() for every class with [InngestFunction] that derives from InngestFunction<TEventData> or InngestFunction<TEventData, TResult> and that generated code in the project can create and name, in the order of their names, and returns the builder. internal unless the project says public.

The MSBuild properties of the project that the generator and the analyzers read:

Property Default Purpose
InngestGenerateFunctionRegistration false true writes the method and reports the classes it leaves out (INNGEST001 to INNGEST005). Nothing is written or reported until it is set.
InngestFunctionsMethodName AddInngestFunctions The name of the generated method.
InngestFunctionsAccessibility internal public or internal.
DisableInngestAnalyzers false true removes everything the package runs in the compiler, the generator and both analyzers, from the build.
PublishAot, PublishTrimmed, JsonSerializerIsReflectionEnabledByDefault Read by the JSON analyzer, which is active when reflection-based JSON is off.

The diagnostics:

Id Severity Reported when
INNGEST001 Warning A class has [InngestFunction] but is not a function.
INNGEST002 Warning An abstract class has [InngestFunction]; it is not registered.
INNGEST003 Warning A generic class has [InngestFunction]; it is not registered.
INNGEST004 Warning A private, protected, private protected or file-local class, or one inside such a type, has [InngestFunction]; it is not registered.
INNGEST005 Warning A function class has no public constructor; it is not registered.
INNGEST006 Warning InngestGenerateFunctionRegistration, InngestFunctionsMethodName or InngestFunctionsAccessibility has a value the generator cannot use.
INNGEST010 Warning The event data or result of a function, or a type a typed step saves (RunAsync<T>, WaitForEventAsync<T>, InvokeAsync, PublishAsync<T> and the others), is in no JsonSerializerContext, and reflection-based JSON is off. A code fix lists it.
INNGEST011 Warning The same type is anonymous, which no context can list.

Package Inngest.EntityFrameworkCore. See Transactional outbox.

Member Purpose
ModelBuilder.AddInngestOutbox(Action<EntityTypeBuilder<InngestOutboxMessage>>?) Maps the InngestOutbox table in the model of a DbContext; the callback changes the mapping, for example its name or schema. In Microsoft.EntityFrameworkCore.
DbContextOptionsBuilder.UseInngestOutbox() Lets saves wake the dispatcher once they have committed, instead of at the next poll. Works wherever the options are built, with or without a service provider. In Microsoft.EntityFrameworkCore.
DbContextOptionsBuilder.UseInngestOutbox(IServiceProvider) The same, and fails when the options are built if AddEntityFrameworkOutbox was not called. In Microsoft.EntityFrameworkCore.
DbContext.AddInngestEvent<T>(T data, string? id = null) Adds the data as an event named T.EventName to the unit of work, serialized with the SDK’s serializer options, and returns the row. The id is generated unless given. In Microsoft.EntityFrameworkCore.
DbContext.AddInngestEvent(InngestEvent @event) The same for an InngestEvent, which keeps its Id, User, Timestamp, Version and the sessions of Meta. In Microsoft.EntityFrameworkCore.

InngestOutboxMessage, the entity of the table, with all times in UTC: Id (the key, and the id the event is sent under; at most 255 characters, as Name and Version are), Name, Data, User and Sessions (JSON text), Version, Timestamp (the event’s own time, which the code may set), CreatedAt (when the row was added), NextAttemptAt, Attempts, LastError, LeaseToken, LeaseExpiresAt and SentAt.

InngestOutboxOptions:

Member Purpose
DispatcherEnabled Runs the dispatcher in this process. true by default.
PollInterval How long the dispatcher waits for a wake-up before it looks anyway. 5 seconds by default.
BatchSize The most events one claim takes and one request sends. 100 by default.
LeaseDuration, SendTimeout How long a dispatcher owns the events it claimed (1 minute) and how long one request may take (20 seconds). The lease must be at least twice the timeout.
RetryDelay, MaxRetryDelay The wait after the first failed attempt, doubled with each failure, and its cap. 5 seconds and 5 minutes by default.
Retention, CleanupInterval, CleanupBatchSize How long sent events stay (1 day), how often older ones are deleted (5 minutes) and how many one DELETE removes (1000).

Package Inngest.SignalR, which also brings in Inngest.AspNetCore. See SignalR.

Member Purpose
IServiceCollection.AddInngestSignalR(Action<InngestSignalROptions>) Registers the bridge for InngestRealtimeHub. Call AddSignalR and AddInngest as well. In Microsoft.Extensions.DependencyInjection.
IServiceCollection.AddInngestSignalR<THub>(Action<InngestSignalROptions>) Registers the bridge for a hub of your own, which injects InngestRealtimeBridge<THub>. The options are read at once, so a missing Authorize fails the app at startup.
IEndpointRouteBuilder.MapInngestRealtimeHub(string pattern) Maps InngestRealtimeHub and returns its HubEndpointConventionBuilder. In Microsoft.AspNetCore.Builder.
IEndpointRouteBuilder.MapInngestRealtimeHub(string pattern, Action<HttpConnectionDispatcherOptions>) The same, with the options of the connections that MapHub takes, such as CloseOnAuthenticationExpiration.

InngestRealtimeHub, a sealed hub with Subscribe(string channel, string[] topics) and Unsubscribe(string channel, string[] topics).

InngestRealtimeBridge<THub> forwards the messages to the clients of THub. It sends to connections by id, never to a group, so that instances on a backplane deliver each message once.

Member Purpose
SubscribeAsync(HubCallerContext caller, string channel, IReadOnlyList<string> topics, CancellationToken) ValueTask<RealtimeSubscription>: asks Authorize, joins the caller and returns what it joined. Joining again changes nothing. Throws HubException when the request is incomplete, refused, over the limit, or the app is stopping.
SubscribeAsync<T>(HubCallerContext caller, RealtimeTopic<T> topic, CancellationToken) The same for a typed topic.
Unsubscribe(HubCallerContext caller, string channel, IReadOnlyList<string> topics) Takes the caller out of what it joined with these arguments, or with the subscription Authorize returned. Leaving what it is not in changes nothing.
Unsubscribe<T>(HubCallerContext caller, RealtimeTopic<T> topic) The same for a typed topic.

InngestSignalROptions:

Member Purpose
Authorize Func<RealtimeSubscribeRequest, ValueTask<RealtimeSubscription?>>, required: returns the subscription to join, which may have fewer topics or another channel, or null to refuse.
MessageMethod The client method that receives each message as a string of JSON. "Realtime" by default.
ErrorMethod The client method that hears of a subscription the client lost, with the channel and topics it asked for and the reason: "behind", "send-failed" or "inngest-ended". The connection stays open. "RealtimeError" by default.
MaxSubscriptionsPerConnection How many subscriptions one connection may be in, counting each way it asked to join. 32 by default.
MaxQueuedMessagesPerConnection How many messages may wait for one connection. A connection that reaches it loses its subscriptions and is told. At least MaxSubscriptionsPerConnection. 512 by default.

RealtimeSubscribeRequest(HubCallerContext caller, RealtimeSubscription requested, IServiceProvider services, CancellationToken cancellationToken = default), with Caller, Requested, Services (a scope of its own for each request) and CancellationToken. The bridge makes one for each client that asks to join, and a test can make one to call Authorize directly.

Package Inngest.Blazor, for Blazor Server, WebAssembly and interactive Auto. See Realtime in Blazor.

RealtimeView<TData>, a component that draws nothing of its own. It subscribes after its first interactive render, never while prerendering, and unsubscribes when it is disposed.

Member Purpose
Topic The RealtimeTopic<TData> to watch.
Channel, Topics Several topics of a channel, instead of Topic. TData must then be JsonElement.
MaxMessages How many of the newest messages RealtimeState.Messages keeps. 100 by default.
OnMessage An EventCallback<RealtimeMessage<TData>> called for each message, in order.
ThrowOnError Hands a failed subscription to the nearest ErrorBoundary. false by default.
ChildContent A RenderFragment<RealtimeState<TData>>.
Restart() Subscribes again with the messages cleared, such as after a failure.

RealtimeState<TData>: Connection, Error, Messages, Latest, LatestByTopic and TextByTopic, the text of the newest stream of each topic. RealtimeConnectionState is Idle, Connecting, Open, Reconnecting, Closed or Failed.

IRealtimeSource is what the component asks for, and what code outside components can inject:

Method Returns
SubscribeAsync<T>(RealtimeTopic<T> topic, CancellationToken) IAsyncEnumerable<RealtimeMessage<T>>: the topic’s messages from now on
SubscribeAsync(string channel, IReadOnlyList<string> topics, CancellationToken) IAsyncEnumerable<RealtimeMessage<JsonElement>> for several topics of a channel
The same two with an Action<RealtimeConnectionState>? onConnectionChanged before the token The same, and a source that can tell calls the callback with Connecting, Open and Reconnecting. An implementation writes these two.

Each side registers its own source. An app that registers both gets the one registered last.

RealtimeRelayOptions: Url, which maps a channel and its topics to the address of the endpoint, and SerializerOptions, which read the data of typed topics.

Packages Inngest.UserContext and Inngest.UserContext.AspNetCore. See User context.

Member Purpose
IInngestBuilder.AddUserContext(Action<UserContextOptions>?) Adds the middleware that attaches the allowed claims of the current user to the events an app sends and restores them in runs, and registers ICurrentUser and a scoped ClaimsPrincipal. Needs Data Protection, or an IUserContextProtector. Register it before middleware that needs the user.
IInngestBuilder.AddUserContextFromHttpContext() Package Inngest.UserContext.AspNetCore. Makes HttpContext.User the user of events sent while serving a request.
InvokeOptions.WithUser(FunctionContext) Extension method. Passes the user of the run to the function being invoked. Invocations do not pass through middleware, so they carry the user only when asked.

ICurrentUser: Principal, a ClaimsPrincipal that is anonymous without a user; IsAuthenticated; and IssuedAt, when the sender took the claims. It is the user of the run whose code is running, in every scope.

UserContextOptions:

Member Purpose
Claims The claim types that are attached, matched exactly. sub and ClaimTypes.NameIdentifier by default.
Lifetime How long after the claims were taken a run can still start with them, judged by the later of its creation and its event’s timestamp. Seven days by default.
MaxSize The largest size of the payload’s JSON in UTF-8 bytes. 4096 by default; a larger user is not attached.
Propagate Whether the events a run sends carry its user. true by default.
EventFilter A Func<InngestEvent, bool> that picks the events that carry the user. null means all.
OnInvalid An InvalidUserContextAction: Anonymous (default) runs without a user and logs a warning, FailRun fails the run. A failure handler never fails on its user.

IUserContextSource: GetUserAsync(CancellationToken) returns the ClaimsPrincipal an event sent outside a run is sent for, or null. IUserContextProtector: Protect(string) and TryUnprotect(string, out string?), which turn the JSON of the claims into text for the event and back; ASP.NET Core Data Protection by default.

Package Inngest.Webhooks, which Inngest.AspNetCore brings in; MapInngestWebhook is in Inngest.AspNetCore. See Webhooks.

WebhookProvider says how a source of webhooks is verified and how its deliveries become events. Its constructor (string name, IWebhookVerifier verifier, Func<WebhookDelivery, InngestEvent?> createEvent) takes any other source. The factories:

Factory Event
Stripe(string secret, TimeSpan? tolerance = null) stripe/<type>, the Stripe event as data, its id as the id. Also with IEnumerable<string> secrets.
GitHub(string secret) github/<X-GitHub-Event>, the payload as data, X-GitHub-Delivery as the id; the name and the id are unsigned headers, and a delivery without the id is a 400. Also with IEnumerable<string> secrets.
Shopify(string secret) shopify/<topic> with dots for slashes, the payload as data, X-Shopify-Webhook-Id as the id; the topic and the id are unsigned headers, and a delivery without the id is a 400. Also with IEnumerable<string> secrets.
StandardWebhooks(string eventPrefix, string secret, TimeSpan? tolerance = null) <prefix>/<type>, the data of the payload as data, webhook-id or svix-id as the id. Also with IEnumerable<string> secrets.
Hmac(string eventName, HmacWebhookOptions options, string secret) The one name, the payload as data, the header options names as the id, which a delivery must then have; no id without such a header. Also with IEnumerable<string> secrets.

WebhookOptions, an immutable record:

Member Purpose
MaxBodySize The largest body accepted, in bytes; a larger request is answered with 413. 1 MiB by default.
SendTimeout How long to wait for Inngest to accept the event before answering 503. Four seconds by default.
Transform Func<WebhookDelivery, InngestEvent, InngestEvent?>: changes the event before it is sent, or returns null to drop the delivery with 204. A JsonElement as the Data or User it returns is copied before the send.

WebhookDelivery, what a Transform and a provider’s createEvent see: Provider, DeliveryId, Payload (a JsonElement, valid while the request is handled), Services and GetHeader(string name). Its constructor (string provider, string? deliveryId, JsonElement payload, IWebhookRequest? request = null) is public, to try a Transform in a test.

An event that cannot be sent is answered with a client error, not a 503: 413 when Inngest says it is too large, 400 for another client error of Inngest, for a refusal of the client and for a payload that cannot be written as JSON. See Webhooks.

Verifiers. Each takes a secret or several, so that a secret can be replaced without downtime, and checks a request with Verify(IWebhookRequest request, DateTimeOffset now), which returns a WebhookVerification and never throws for what a request contains.

Type Scheme
StandardWebhooksVerifier webhook-id, webhook-timestamp and webhook-signature, or the svix- headers: HMAC-SHA256 of {id}.{timestamp}.{body}, keyed with the base64 after whsec_; only v1 signatures; a tolerance of five minutes by default
StripeWebhookVerifier Stripe-Signature, t= and v1=: HMAC-SHA256 of {t}.{body}, keyed with the text of the secret; a tolerance of five minutes by default
GitHubWebhookVerifier X-Hub-Signature-256, sha256= and the hex HMAC-SHA256 of the body; delivery id from X-GitHub-Delivery, which the signature does not cover
ShopifyWebhookVerifier X-Shopify-Hmac-Sha256, the base64 HMAC-SHA256 of the body; delivery id from X-Shopify-Webhook-Id, which the signature does not cover
HmacWebhookVerifier Any HMAC of the body, with HmacWebhookOptions

HmacWebhookOptions, an immutable record: SignatureHeader (required), Algorithm (HashAlgorithmName, SHA-256 by default), SignatureEncoding (HmacSignatureEncoding.Hex or Base64), SignaturePrefix, TimestampHeader, SignedContentPrefix, TimestampSeparator, Tolerance and DeliveryIdHeader.

To verify another source, implement IWebhookVerifier. IWebhookRequest is the request it sees, independent of the web framework: Body (the raw bytes, owned by the host and read in place), GetHeader(string name) and Services. WebhookVerification is a result: Valid(string? deliveryId = null) or Invalid(string reason), with IsValid, DeliveryId and Reason; the default value is not valid.

Package Inngest.Testing, namespace Inngest.Testing. See Testing functions.

Member Purpose
InngestTestHost(IServiceCollection services) Builds the app’s services from a copy of the collection, with nothing sent to Inngest.
RunAsync(string functionId, InngestEvent @event, StepMocks mocks, CancellationToken) Runs the function until it completes, fails for good or waits on a step without a mock. Also without mocks, and with an IReadOnlyList<InngestEvent> for a batch.
RunAsync<TFunction>(InngestEvent @event, StepMocks mocks, CancellationToken) The same for the function registered as TFunction, with the same overloads.
ExecuteStepAsync(string functionId, string stepId, InngestEvent @event, StepMocks mocks, CancellationToken) Runs the function until the step has run, or has been reached when Inngest carries it out. Also without mocks.
ExecuteStepAsync<TFunction>(string stepId, InngestEvent @event, StepMocks mocks, CancellationToken) The same for the function registered as TFunction. Also without mocks.
SentEvents Every event sent through the app’s client since the host was created.
SentSignals Every signal sent through the app’s client since the host was created. None resumes a run.
Published Every realtime message published since the host was created, as PublishedMessage(RealtimeTopic Topic, JsonElement Data) with IsStream for a stream, recorded with all its text. Tokens the host mints are placeholders, and subscribing fails.
Services The app’s services, as functions resolve them. Disposing the host, which is IAsyncDisposable and IDisposable, disposes them.

StepMocks answers steps by id, and every method returns a new set: Run<T>(id, T result), Run<T>(id, Func<int, T> handler), RunThrows(id, exception), Sleep(id), AllSleeps(), WaitForEvent(id, received), WaitForEventTimeout(id), Invoke<T>(id, T result), Invoke<TFunction, TResult>(id, TResult result), InvokeThrows(id, exception), WaitForSignal<T>(id, T data), WaitForSignalTimeout(id), SendSignal(id, runId), Fetch(id, statusCode, body, headers) and Infer<T>(id, T response). A Run mock also answers an AI wrap step.

TestRun: RunId, FunctionId, Status, Output, GetOutput<T>(), Error, Steps, GetStep(id), WaitingOn, SentEvents, SentSignals, Published and FailureHandler; ToString() describes the outcome. Status is a TestRunStatus: Completed, Failed, Waiting or Stopped.

TestStep: Id, HashedId, Type, Op, Options, Status, Attempts, Mocked, Output, GetOutput<T>(), Error and Errors. Status is a TestStepStatus: Pending, Completed or Failed.

Package Inngest.Testing.Containers, namespace Inngest.Testing.Containers. See Testing with containers. It follows the Testcontainers module pattern: a builder, a container and a configuration.

InngestServerBuilder(string image) builds an InngestServerContainer for the dev server. There is no default image; the module is tested with inngest/inngest:v1.49.0. It takes an IImage as well, and has the methods of every Testcontainers builder.

Member Purpose
WithSelfHosting() Runs inngest start, the self-hosted server, in place of the dev server.
WithSigningKey(string), WithEventKey(string) Sets the keys of the self-hosted server. Keys left out are generated. The signing key must be hexadecimal digits in pairs.
WithAppUrl(Uri), WithAppUrl(string) Has the server sync the app at this address when it starts and retry every second until the app answers. A loopback address becomes host.docker.internal.
WithConnectGateway(int? port = null) Publishes the Connect gateway on the same port inside the container and on the host, and waits for it. A free port when none is given, kept from other processes until the container starts.
WithFastTiming(bool = true) The timing flags that make runs finish quickly: a sync retried and a step retried after a second, the queue polled every 50 ms. On by default.
InngestServerBuilder.InngestPort The port of the server’s API inside the container, 8288.

InngestServerContainer, a DockerContainer:

Member Purpose
GetBaseAddress() The address of the server’s API as the test reaches it, as a Uri. GetConnectionString() returns it as text.
Configure(InngestOptions) Sets an app’s options to use the server: dev mode and the address, or cloud mode with the keys and the address. Replaces addresses set in code.
GetSdkEnvironment() The same settings as INNGEST_* variables, for a process that inherits others: INNGEST_DEV (the dev server’s address, or 0 for the self-hosted server), INNGEST_BASE_URL, INNGEST_API_BASE_URL and INNGEST_EVENT_API_BASE_URL, and INNGEST_SIGNING_KEY and INNGEST_EVENT_KEY for the self-hosted one.
SyncAsync(Uri appUrl, CancellationToken) Has the server register the app that listens at this address. A loopback address, or 0.0.0.0 or [::], goes out as host.docker.internal; any other address as given. The request names the kind of server (dev or cloud) and is signed for the self-hosted server. Throws when the app does not register.
IsDevServer, SigningKey, EventKey, ConnectGatewayPort Which server it is, the keys of the self-hosted server (null for the dev server) and the gateway’s port (null without one).
StartAsync(CancellationToken) Starts the container. A server that does not become ready fails with its log in the exception.

InngestServerConfiguration holds what the builder keeps for the container: SelfHosted, SigningKey, EventKey, AppUrls, ConnectGateway, ConnectGatewayPort and FastTiming, next to the settings of any container.

Package Inngest.Testing.Containers.AspNetCore for .NET 10, namespace Inngest.Testing.Containers. See An app under WebApplicationFactory.

Member Purpose
InngestWebApplicationFactory<TEntryPoint>(InngestServerContainer inngest, string servePath = "/api/inngest") A WebApplicationFactory that runs the app on Kestrel, on all interfaces and a free port, and applies inngest.Configure to the app’s options after the app’s own. The container must be running when the app starts.
StartAsync(CancellationToken) Starts the app and has the container sync it, so the server knows its functions when this returns.
GetAppUrl() The address of the app’s Inngest endpoint as the test reaches it.
CreateClient(), CreateClient(WebApplicationFactoryClientOptions) Declared again, so that a client reaches the app at localhost and its port, also with options that have no base address. CreateDefaultClient gets the same address.
Container The container the app is configured for.

Packages Inngest.Templates and dotnet-inngest. They have no C# API: the first holds dotnet new templates and the second is a .NET tool. See Templates and tool.

Templates, installed with dotnet new install Inngest.Templates:

Short name Project SDK References
inngest-web Microsoft.NET.Sdk.Web Inngest.AspNetCore, at the version of the template package
inngest-worker Microsoft.NET.Sdk.Worker Inngest.Connect, at the version of the template package, and Microsoft.Extensions.Hosting
Option Templates Meaning
-n, --name both The project name, and the app id in kebab case.
-f, --framework both net10.0 (the default) or net8.0.
--http-port inngest-web The port of the http launch profile. A free port from 5000 to 5300 by default.
--no-restore both Skips the restore after the project is made.

dotnet inngest, installed with dotnet tool install --global dotnet-inngest (the command is dotnet-inngest):

Command Purpose
dotnet inngest dev [options] [-- <options of inngest dev>] Downloads the Inngest CLI release on first use, checks its SHA-256 and runs inngest dev.
dotnet inngest --version Prints the version of the tool and of the CLI it is pinned to.
dotnet inngest --help Prints the usage.
Option of dev Meaning
-u, --sdk-url <url> The app’s Inngest endpoint, passed to the CLI. Without it, and without --no-discovery, the tool reads the http address of the first profile that runs the project in Properties/launchSettings.json and appends /api/inngest.
--project <path> The folder or project file whose launch settings are read. The current folder by default.
--cli-version <version> Runs another release of the CLI. Its download is checked against the checksums.txt of the release; the pinned version against checksums built into the tool.

Other options go to inngest dev as they are, in order. INNGEST_DOTNET_CACHE sets the folder the CLI is kept in. The exit code is the CLI’s; the tool’s own are 1 when the CLI cannot be had (a request failed, or a download does not match its SHA-256), 2 for a command line it cannot read and 130 when Ctrl+C stops a download.

inngest-dotnet is a community Inngest SDK for .NET. It is not affiliated with or endorsed by Inngest Inc.