Skip to content

Get started

Get a durable workflow running in about five minutes, using your app and a Postgres connection string.

  • .NET 8.0 or later
  • A reachable Postgres instance (any flavor: local, Docker, RDS, Supabase, Neon)
Terminal window
dotnet add package PgWorkflows

Point the builder at your Postgres connection string and register your workflows and activities. The hosted worker is configured for you.

builder.Services.AddPgWorkflows(pg =>
pg.UsePostgres(connectionString)
.AddWorkflow<GreetingWorkflow>()
.AddActivities<HelloActivities>()
);

The tables PgWorkflows needs are created automatically on startup (idempotently, safe across many instances starting at once). Pass ensureSchemaOnStart: false to UsePostgres if your deployment applies schema out-of-band instead.

A workflow is an ordinary C# class; activities hold the side effects.

[Workflow("greeting")]
public sealed class GreetingWorkflow
{
[WorkflowRun]
public async ValueTask<string> RunAsync(
IWorkflowContext ctx,
string name,
CancellationToken cancellationToken
)
{
return await ctx.Activity(
(HelloActivities a) => a.Hello(name),
cancellationToken
);
}
}
public sealed class HelloActivities
{
[Activity("hello")]
public string Hello(string name) => $"Hello, {name}!";
}
var workflows = app.Services.GetRequiredService<IPgWorkflowClient>();
var result = await workflows.ExecuteAsync<GreetingWorkflow, string, string>("Postgres");

result is "Hello, Postgres!". The interesting part is what’s now in your database. The run, its durable step, and the activity job are all plain rows:

select workflow_name, status, result from pw_workflow_runs;
workflow_name | status | result
---------------+-----------+---------------------
greeting | succeeded | "Hello, Postgres!"

Everything PgWorkflows knows lives in tables like this one; see what’s in your database for the tour.