NexJob 0.4.0
See the version list below for details.
dotnet add package NexJob --version 0.4.0
NuGet\Install-Package NexJob -Version 0.4.0
<PackageReference Include="NexJob" Version="0.4.0" />
<PackageVersion Include="NexJob" Version="0.4.0" />
<PackageReference Include="NexJob" />
paket add NexJob --version 0.4.0
#r "nuget: NexJob, 0.4.0"
#:package NexJob@0.4.0
#addin nuget:?package=NexJob&version=0.4.0
#tool nuget:?package=NexJob&version=0.4.0
<div align="center">
<br/>
███╗ ██╗███████╗██╗ ██╗ ██╗ ██████╗ ██████╗
████╗ ██║██╔════╝╚██╗██╔╝ ██║██╔═══██╗██╔══██╗
██╔██╗ ██║█████╗ ╚███╔╝ ██║██║ ██║██████╔╝
██║╚██╗██║██╔══╝ ██╔██╗ ██ ██║██║ ██║██╔══██╗
██║ ╚████║███████╗██╔╝ ██╗╚█████╔╝╚██████╔╝██████╔╝
╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝
Background jobs for .NET that stay out of your way.
<br/>
</div>
What is NexJob?
NexJob is a modern, open-source background job framework for .NET built for predictable execution, time-sensitive workflows, and explicit failure handling.
Unlike Hangfire — which relies on serialization magic and delayed async — NexJob is async/await native, fully type-safe, and stateless. Jobs run in isolated DI scopes with zero hidden state. Storage is the source of truth. Failures are explicit.
⚡ 30-Second Quick Start
1. Define a job
public class SendInvoiceJob : IJob<SendInvoiceInput>
{
private readonly IEmailService _email;
public SendInvoiceJob(IEmailService email) => _email = email;
public async Task ExecuteAsync(SendInvoiceInput input, CancellationToken ct)
=> await _email.SendAsync(input.Email, "Invoice attached", ct);
}
2. Register
builder.Services.AddNexJob(builder.Configuration)
.AddNexJobJobs(typeof(Program).Assembly);
3. Enqueue
await scheduler.EnqueueAsync<SendInvoiceJob, SendInvoiceInput>(
new(orderId, email));
Done. The job executes immediately on an available worker.
🔥 Why NexJob?
| Feature | Benefit |
|---|---|
| Predictable execution | No serialization magic, no hidden state. Jobs run in isolated DI scopes. |
Deadline support (deadlineAfter) |
Mark jobs expired if not started in time — essential for time-sensitive operations. |
| Automatic dead-letter handling | Failed jobs trigger explicit handlers for alerts, compensation, or cleanup. |
| Low-latency dispatch | Wake-up signaling eliminates polling delay on local enqueue. 2.87× faster than Hangfire. |
| All storage free | PostgreSQL, SQL Server, Redis, MongoDB — no paid adapters or license walls. |
| Async/await native | True async from the ground up. No serialization hacks. |
| Live config | Pause queues, adjust workers, change polling — all at runtime without restart. |
| Schema migrations | Auto-migrations on startup. No manual SQL. No deployment breakage. |
⚔️ NexJob vs Hangfire
| NexJob | Hangfire | |
|---|---|---|
| License | MIT | LGPL / paid Pro |
| Async/await native | ✅ | ❌ serialization-based |
| Deadline support | ✅ deadlineAfter |
❌ |
| Dead-letter handlers | ✅ DI-based | ❌ |
| Priority queues | ✅ | ❌ |
| Resource throttling | ✅ [Throttle] |
❌ |
| Per-job retry config | ✅ [Retry] |
❌ |
| Execution windows | ✅ | ❌ |
| Live config | ✅ | ❌ |
| Schema migrations | ✅ auto | ❌ |
| Graceful shutdown | ✅ | ❌ |
| OpenTelemetry | ✅ built-in | ❌ |
| Payload versioning | ✅ IJobMigration |
❌ |
| All adapters free | ✅ | ❌ Redis/MongoDB paid |
| Storage providers | 5 (all open-source) | 3 |
| Enqueue latency | 9.28 μs | 26.63 μs |
📦 Installation
# Core
dotnet add package NexJob
# Storage (pick one — all free)
dotnet add package NexJob.Postgres
dotnet add package NexJob.SqlServer
dotnet add package NexJob.Redis
dotnet add package NexJob.MongoDB
# Dashboard
dotnet add package NexJob.Dashboard
Features in Depth
Scheduling
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)
await scheduler.RecurringAsync<ReportJob, ReportInput>(
id: "monthly",
input: new(DateTime.UtcNow.Month),
cron: "0 9 1 * *");
Continuations (chaining)
var paymentId = await scheduler.EnqueueAsync<ProcessPaymentJob, PaymentInput>(input);
await scheduler.ContinueWithAsync<SendReceiptJob, ReceiptInput>(paymentId, receiptInput);
Reliability
Global retry policy
By default, jobs retry with exponential backoff. Configure via appsettings.json:
{ "NexJob": { "MaxAttempts": 5 } }
Per-job retry
[Retry(5, InitialDelay = "00:00:30", Multiplier = 2.0, MaxDelay = "01:00:00")]
public class PaymentJob : IJob<PaymentInput> { ... }
Dead-letter handler
Automatically handle jobs that exhaust retries:
public class PaymentDeadLetterHandler : IDeadLetterHandler<PaymentJob>
{
public async Task HandleAsync(JobRecord failedJob, Exception lastException, CancellationToken ct)
=> await _alerts.SendAsync($"Payment failed", ct);
}
builder.Services.AddTransient<IDeadLetterHandler<PaymentJob>, PaymentDeadLetterHandler>();
Graceful shutdown
Jobs complete naturally on SIGTERM. Strays are requeued by orphan watcher.
Deadlines
Jobs not executed within the deadline are marked Expired and skipped:
await scheduler.EnqueueAsync<PaymentJob, PaymentInput>(
input,
deadlineAfter: TimeSpan.FromMinutes(5));
Observability
OpenTelemetry (zero config)
builder.Services.AddOpenTelemetry()
.WithTracing(t => t.AddSource("NexJob"))
.WithMetrics(m => m.AddMeter("NexJob"));
Metrics: nexjob.jobs.enqueued, nexjob.jobs.succeeded, nexjob.jobs.failed, nexjob.jobs.expired, nexjob.job.duration.
Job context
public class ImportJob : IJob<ImportInput>
{
private readonly IJobContext _ctx;
public ImportJob(IJobContext ctx) => _ctx = ctx;
public async Task ExecuteAsync(ImportInput input, CancellationToken ct)
{
await _ctx.ReportProgressAsync(0, "Starting...", ct);
// ... do work ...
await _ctx.ReportProgressAsync(100, "Done.", ct);
}
}
Job tags
await scheduler.EnqueueAsync<SendInvoiceJob, SendInvoiceInput>(
input,
tags: ["tenant:acme", $"invoice:{invoiceId}"]);
var jobs = await scheduler.GetJobsByTagAsync("tenant:acme");
Concurrency & Throttling
Resource throttling
[Throttle(resource: "stripe", maxConcurrent: 3)]
public class ChargeCardJob : IJob<ChargeInput> { ... }
Execution windows
Restrict queues to specific times:
{
"NexJob": {
"Queues": [
{
"Name": "reports",
"Workers": 2,
"ExecutionWindow": {
"StartTime": "22:00",
"EndTime": "06:00",
"TimeZone": "America/Sao_Paulo"
}
}
]
}
}
Payload Versioning
Handle evolving job inputs gracefully:
[SchemaVersion(2)]
public class SendInvoiceJob : IJob<SendInvoiceInputV2> { ... }
public class Migration : IJobMigration<SendInvoiceInputV1, SendInvoiceInputV2>
{
public SendInvoiceInputV2 Migrate(SendInvoiceInputV1 old)
=> new(old.OrderId, old.Email, Language: "en-US");
}
builder.Services.AddJobMigration<SendInvoiceInputV1, SendInvoiceInputV2, Migration>();
Dashboard
Web API:
app.UseNexJobDashboard("/dashboard");
Worker Service / Console App:
services.AddNexJobStandaloneDashboard(configuration);
// Dashboard at http://localhost:5005/dashboard
Configuration
appsettings.json
{
"NexJob": {
"Workers": 10,
"MaxAttempts": 5,
"PollingInterval": "00:00:05",
"ShutdownTimeoutSeconds": 30,
"DefaultQueue": "default",
"Queues": [
{ "Name": "critical", "Workers": 3 },
{ "Name": "default", "Workers": 5 }
]
}
}
Code configuration
builder.Services.AddNexJob(builder.Configuration, opt =>
{
opt.UsePostgres(connectionString);
opt.Workers = 10;
opt.MaxAttempts = 5;
});
Storage Providers
All open-source. No license walls.
| Package | Storage | Status |
|---|---|---|
NexJob |
In-memory | Production ready |
NexJob.Postgres |
PostgreSQL 14+ | Production ready |
NexJob.SqlServer |
SQL Server 2019+ | Production ready |
NexJob.Redis |
Redis 7+ | Production ready |
NexJob.MongoDB |
MongoDB 6+ | Production ready |
NexJob.Oracle |
Oracle 19c+ | Planned |
Testing
The in-memory provider is built-in:
services.AddNexJob(); // InMemory by default
Project
Roadmap
v0.4.0 ✅ Wake-up channel · Deadlines · Dead-letter handlers · README updated
v1.0.0 ○ Stable API · production-ready
Contributing
NexJob is open-source. Issues, PRs, and ideas welcome.
git clone git@github.com:oluciano/NexJob.git
cd NexJob && dotnet test
See CONTRIBUTING.md for details.
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 | Versions 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. |
-
net8.0
- Cronos (>= 0.8.4)
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 8.0.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Diagnostics.HealthChecks (>= 8.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- System.Diagnostics.DiagnosticSource (>= 8.0.1)
NuGet packages (6)
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 |
|---|---|---|
| 1.0.0 | 83 | 4/8/2026 |
| 0.8.0 | 78 | 4/8/2026 |
| 0.7.0 | 123 | 4/7/2026 |
| 0.6.0 | 162 | 4/3/2026 |
| 0.5.2 | 168 | 4/1/2026 |
| 0.5.1 | 158 | 4/1/2026 |
| 0.5.0 | 168 | 3/31/2026 |
| 0.4.0 | 163 | 3/31/2026 |
| 0.3.2 | 206 | 3/28/2026 |
| 0.3.1 | 219 | 3/28/2026 |
| 0.3.0 | 181 | 3/27/2026 |
| 0.2.0 | 178 | 3/27/2026 |
| 0.1.1 | 131 | 3/27/2026 |
| 0.1.0 | 122 | 3/26/2026 |
| 0.1.0-alpha | 123 | 3/26/2026 |