• EF Core
  • .NET 8, 9 and 10
  • Open source, MIT

Background jobs that commit with your data

XactJobs saves a job in the same EF Core transaction as your business data: if it commits, a worker runs the job, and if it rolls back, the job never existed.

dotnet add package XactJobs

Getting started

Three steps

Tables in your database, two lines at startup, and jobs next to your data.

  1. Create the tables

    Run the install script for your database, from sql/.

    sqlcmd -I -d <db> -i xact-jobs-sqlserver.sql

    xact-jobs-sqlserver.sql

    Or include them in your EF migrations, with ApplyXactJobsConfigurations(..., excludeFromMigrations: false).

    Install and upgrade scripts
  2. Configure startup

    Add the entity configurations to your DbContext, and register the workers.

    // UserDbContext.OnModelCreating
    modelBuilder
        .ApplyXactJobsConfigurations(
            Database.ProviderName);
    
    // Program.cs: 2 workers
    builder.Services
        .AddXactJobs<UserDbContext>();
    All the options
  3. Fire away

    Enqueue on your DbContext and save. The job runs when your transaction commits.

    db.Orders.Add(order);
    
    db.JobEnqueue<Mailer>(x =>
        x.SendConfirmation(order.Number));
    
    // one transaction: order and job
    await db.SaveChangesAsync();
    Writing jobs

Features

Jobs as part of your data

Everything runs in your app and your database, with the transactions you already have.

Transactional enqueue

Enqueue a job on your DbContext, next to your data. If your transaction rolls back, the job never existed.

Retries and cancellation

A failed job runs again, waiting longer each time. A job that can never succeed stops itself, without retries.

Dashboard and REST API

See the pending, finished and periodic jobs and the batches. Run, retry, pause and trigger them.

Five databases, no extra server

SQL Server, PostgreSQL, MySQL, Oracle and SQLite, on .NET 8, 9 and 10. The jobs live in your database, the workers in your app.

Dashboard

See and manage the jobs

The XactJobs.UI package adds a dashboard and a REST API to your app.

The dashboard: due, running, succeeded and failed jobs, and the jobs processed per hourThe dashboard: due, running, succeeded and failed jobs, and the jobs processed per hour

The dashboard: due, running, succeeded and failed jobs, and the jobs processed per hour

Pages, actions and the API

Measured

Throughput and status

Throughput

2,300–2,600 no-op jobs per second

Draining 20,000 jobs on a Hetzner Cloud CX33 (4 shared vCPUs, 8 GB) with PostgreSQL 16, each job in its own transaction.

The benchmark, to run on your machine

Status: pre-1.0

The core is tested on all five databases, with an integration test suite running against each one (SQLite in-process, the others in containers): transactional enqueue, claiming and leasing, retries, batches and continuations, and periodic jobs.

  • The API can still change between minor versions (0.x). Breaking changes are listed in the release notes, with how to migrate.
  • Schema changes ship as SQL scripts, one per version and database. Existing data is always kept.
  • 1.0 freezes the API and the schema under semantic versioning.

Feedback and issue reports are very welcome, especially from production use. XactJobs was started in 2025, and written without AI. Newer releases are developed with AI, and the changes are reviewed by a human.

Licensed under the MIT License.