NexJob 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package NexJob --version 0.1.0
                    
NuGet\Install-Package NexJob -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NexJob" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NexJob" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="NexJob" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NexJob --version 0.1.0
                    
#r "nuget: NexJob, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NexJob@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NexJob&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=NexJob&version=0.1.0
                    
Install as a Cake Tool

<div align="center">

<br/>

███╗   ██╗███████╗██╗  ██╗     ██╗ ██████╗ ██████╗
████╗  ██║██╔════╝╚██╗██╔╝     ██║██╔═══██╗██╔══██╗
██╔██╗ ██║█████╗   ╚███╔╝      ██║██║   ██║██████╔╝
██║╚██╗██║██╔══╝   ██╔██╗ ██   ██║██║   ██║██╔══██╗
██║ ╚████║███████╗██╔╝ ██╗╚█████╔╝╚██████╔╝██████╔╝
╚═╝  ╚═══╝╚══════╝╚═╝  ╚═╝ ╚════╝  ╚═════╝ ╚═════╝

Background jobs for .NET that stay out of your way.

NuGet NuGet Downloads Build License: MIT .NET

<br/>

</div>


NexJob is the background job library that .NET deserved from day one.

No expression trees. No lock-in. No paid tiers for Redis. No wrestling with serialization. Just a clean interface, two lines of configuration, and a scheduler that handles the hard parts — retries, concurrency, cron, observability — while you focus on what your job actually does.

public class WelcomeEmailJob : IJob<WelcomeEmailInput>
{
    public async Task ExecuteAsync(WelcomeEmailInput input, CancellationToken ct)
        => await _email.SendAsync(input.UserId, ct);
}

That's your entire job. NexJob handles the rest.


Why NexJob exists

Every .NET developer has used Hangfire. And every .NET developer has hit the same walls:

  • The Redis adapter costs money. So does the MongoDB one.
  • async/await is bolted on — Hangfire serializes Task, it doesn't await it.
  • The dashboard looks like it was designed in 2014. Because it was.
  • There's no concept of priority queues, resource throttling, or payload versioning.
  • You can't change workers or pause a queue without restarting the server.
  • The license is LGPL for the core and paid for anything production-worthy.

NexJob was built to solve all of that. MIT license, end to end. Every storage adapter open-source. Native async/await from the ground up. Priority queues and idempotency built in. A dark-mode dashboard to inspect every queue, job state, and retry — without touching the code. OpenTelemetry, appsettings.json support, and live runtime config are on the roadmap.


At a glance

✅ = implemented  ·  🔜 = on the roadmap

NexJob Hangfire
License MIT LGPL / paid Pro
async/await native
Priority queues
Idempotency keys
In-memory for testing
Cron / recurring jobs
PostgreSQL + MongoDB adapters free
Dashboard (dark mode)
All storage adapters free
Resource throttling
Job continuations (chaining)
OpenTelemetry built-in 🔜
Payload versioning 🔜
appsettings.json support 🔜
Execution windows per queue 🔜
Live config without restart 🔜

Installation

# Core (includes in-memory provider for dev/tests)
dotnet add package NexJob

# Pick your storage — all free, all open-source
dotnet add package NexJob.Postgres
dotnet add package NexJob.SqlServer
dotnet add package NexJob.Redis
dotnet add package NexJob.MongoDB
dotnet add package NexJob.Oracle

# Optional dashboard
dotnet add package NexJob.Dashboard

Getting started

1 — Define your job

public record SendInvoiceInput(Guid OrderId, string CustomerEmail);

public class SendInvoiceJob : IJob<SendInvoiceInput>
{
    private readonly IInvoiceService _invoices;
    private readonly IEmailService _email;

    public SendInvoiceJob(IInvoiceService invoices, IEmailService email)
    {
        _invoices = invoices;
        _email = email;
    }

    public async Task ExecuteAsync(SendInvoiceInput input, CancellationToken ct)
    {
        var pdf = await _invoices.GenerateAsync(input.OrderId, ct);
        await _email.SendAsync(input.CustomerEmail, pdf, ct);
    }
}

2 — Register

builder.Services.AddNexJob(opt =>
{
    opt.Workers = 10;
    opt.PollingInterval = TimeSpan.FromSeconds(1);
});

// Register your jobs
builder.Services.AddTransient<SendInvoiceJob>();

3 — Schedule

// Fire and forget
await scheduler.EnqueueAsync<SendInvoiceJob, SendInvoiceInput>(
    new(orderId, email));

// Delayed
await scheduler.ScheduleAsync<SendInvoiceJob, SendInvoiceInput>(
    new(orderId, email),
    delay: TimeSpan.FromMinutes(5));

// Recurring (cron) — default: skip if already running
await scheduler.RecurringAsync<MonthlyReportJob, MonthlyReportInput>(
    id: "monthly-report",
    input: new(DateTime.UtcNow.Month),
    cron: "0 9 1 * *");

// Recurring — allow multiple instances in parallel (range-based sharding etc.)
await scheduler.RecurringAsync<ImportChunkJob, ImportChunkInput>(
    id: "import-chunk",
    input: new(ShardId: 0),
    cron: "*/5 * * * *",
    concurrencyPolicy: RecurringConcurrencyPolicy.AllowConcurrent);

// Continuation — runs only after parent succeeds
var jobId = await scheduler.EnqueueAsync<ProcessPaymentJob, PaymentInput>(paymentInput);
await scheduler.ContinueWithAsync<SendReceiptJob, ReceiptInput>(jobId, receiptInput);

// With idempotency key — safe to call multiple times
await scheduler.EnqueueAsync<SendInvoiceJob, SendInvoiceInput>(
    new(orderId, email),
    idempotencyKey: $"invoice-{orderId}");

4 — Dashboard

app.UseNexJobDashboard("/dashboard");

Open /dashboard and see every queue, every job state, every retry — live.


Priority queues

Jobs with Critical priority jump the queue. No workarounds, no separate deployments.

await scheduler.EnqueueAsync<AlertJob, AlertInput>(
    input,
    priority: JobPriority.Critical);   // Critical → High → Normal → Low

Resource throttling

Limit how many instances of a job run concurrently across all workers — no extra infrastructure required.

[Throttle(resource: "stripe", maxConcurrent: 3)]
public class ChargeCardJob : IJob<ChargeInput> { ... }

Recurring concurrency policy

By default, NexJob prevents a recurring job from having more than one active instance at a time. If the previous execution is still running when the cron fires again, the new firing is silently skipped — no duplicates, no queued pile-up.

// SkipIfRunning (default) — safe for jobs that must not overlap
await scheduler.RecurringAsync<SyncInventoryJob, Unit>(
    id:    "sync-inventory",
    input: Unit.Value,
    cron:  "*/5 * * * *");
    // concurrencyPolicy defaults to RecurringConcurrencyPolicy.SkipIfRunning

Some jobs are designed to run in parallel — for example, range-based imports that each process a different shard of data. Use AllowConcurrent to opt out of the overlap guard:

// AllowConcurrent — each firing spawns a new instance regardless of running ones
await scheduler.RecurringAsync<ImportShardJob, ShardInput>(
    id:                "import-shard",
    input:             new(ShardId: myShardId),
    cron:              "*/10 * * * *",
    concurrencyPolicy: RecurringConcurrencyPolicy.AllowConcurrent);

The dashboard shows a ⟳ concurrent badge on any recurring job registered with AllowConcurrent, so the behaviour is always visible at a glance.


Observability

🔜 Coming in v0.6 — OpenTelemetry spans for every job lifecycle event.


Payload versioning

🔜 Coming in v0.6 — migrate job inputs across schema versions without losing queued jobs.


Testing

The in-memory provider requires zero setup:

builder.Services.AddNexJob(opt => opt.Workers = 1);
// InMemoryStorageProvider is the default — no extra config needed

🔜 TestScheduler with ShouldHaveEnqueued assertions coming in v0.6.


Retry policy

Failed jobs retry with exponential backoff and jitter. Dead-lettered jobs are preserved — never silently dropped.

Attempt Delay
1 ~16 seconds
2 ~1 minute
3 ~5 minutes
4 ~17 minutes
5 ~42 minutes

Configure globally:

builder.Services.AddNexJob(opt =>
{
    opt.MaxAttempts = 3;   // default: 10
});

🔜 Per-job [Retry(attempts: 3)] attribute coming in v0.6.


Storage providers

All open-source. No license walls. Ever.

Package Storage Status
NexJob In-memory ✅ Dev and testing
NexJob.Postgres PostgreSQL 14+ SELECT FOR UPDATE SKIP LOCKED
NexJob.MongoDB MongoDB 6+ ✅ Atomic findAndModify
NexJob.SqlServer SQL Server 2019+ 🔜 Coming soon
NexJob.Redis Redis 7+ 🔜 Coming soon
NexJob.Oracle Oracle 19c+ 🔜 Coming soon

Bring your own? Implement IStorageProvider — one interface, ~15 methods.


Configuration reference

// Storage — pick one and register BEFORE AddNexJob (InMemory is the default)
builder.Services.AddNexJobPostgres(connectionString);
builder.Services.AddNexJobMongoDB(connectionString, databaseName: "nexjob");

builder.Services.AddNexJob(opt =>
{
    // Workers & queues
    opt.Workers = 10;
    opt.Queues  = ["default", "critical"];   // polled in order

    // Timing
    opt.PollingInterval   = TimeSpan.FromSeconds(5);
    opt.HeartbeatInterval = TimeSpan.FromSeconds(30);
    opt.HeartbeatTimeout  = TimeSpan.FromMinutes(5);

    // Retries
    opt.MaxAttempts = 5;
});

Roadmap

v0.1  ✅ Core interfaces · in-memory provider · fire-and-forget
v0.2  ✅ PostgreSQL + MongoDB providers · delayed jobs · cron · dashboard (Blazor SSR)
v0.3  ✅ Priority queues · resource throttling ([Throttle]) · job continuations
v0.4  ✅ Recurring job execution status · unit + integration tests · CI pipeline
v0.5  ○ SQL Server · Redis · Oracle providers
v0.6  ○ OpenTelemetry · payload versioning (IJobMigration) · [Retry] per-job
v1.0  ○ Stable API · production-ready · published to NuGet

Contributing

NexJob is built in the open. Issues, ideas, and PRs are welcome.

git clone git@github.com:oluciano/NexJob.git
cd NexJob
dotnet restore
dotnet test

Read CONTRIBUTING.md before opening a PR.


License

MIT © 2025 Luciano Azevedo


<div align="center"> <br/>

Built with obsession over developer experience.

If Hangfire is the past, NexJob is what comes next.

<br/> </div>

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (12)

Showing the top 5 NuGet packages that depend on NexJob:

Package Downloads
NexJob.Dashboard

Blazor SSR dashboard middleware for NexJob — real-time monitoring of background jobs.

NexJob.Postgres

PostgreSQL storage provider for NexJob — the open-source background job scheduler for .NET 8+.

NexJob.MongoDB

MongoDB storage provider for NexJob — the open-source background job scheduler for .NET 8+.

NexJob.SqlServer

SQL Server storage provider for NexJob.

NexJob.Redis

Redis storage provider for NexJob.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.0 0 4/16/2026
2.0.0 135 4/14/2026
1.0.0 164 4/8/2026
0.8.0 161 4/8/2026
0.7.0 158 4/7/2026
0.6.0 164 4/3/2026
0.5.2 170 4/1/2026
0.5.1 161 4/1/2026
0.5.0 170 3/31/2026
0.4.0 165 3/31/2026
0.3.2 208 3/28/2026
0.3.1 222 3/28/2026
0.3.0 183 3/27/2026
0.2.0 181 3/27/2026
0.1.1 133 3/27/2026
0.1.0 127 3/26/2026
0.1.0-alpha 126 3/26/2026