.NET 8  ·  .NET 10  ·  Minimal API

Stop writing
setup code.
Ship features.

.NET Minimal API starter kits with MongoDB, dual pagination, and ErrorOr baked in — Redis, Keycloak, and S3 for the kits that need them. Configure and run.

One-time payment  ·  Unlimited projects  ·  Lifetime access

6 kits
19 hooks
2 pagination modes
1 command to run
FenixKit EMBER
EMBER UPLOADS + Hangfire background jobs
€75 See EMBER →
Launch offer FIRSTXPEOPLE €15 off

Launch Offer — Limited spots

€15 off all kits for early buyers

A small thank-you to the first supporters. Use the code at checkout on any kit.

FIRSTXPEOPLE
SPARK —€35€20 GUARD —€45€30 RAPID —€45€30 FLICK —€55€40 UPLOADS —€65€50 EMBER —€75€60

Pick the stack that fits.

Start minimal, add layers as you need them. Almost every kit includes .NET 8 and .NET 10 (at the same price).

SPARK
SPARK The clean foundation — MongoDB Minimal API starter
  • BaseRepository with 7 overridable hooks: validate (create, update, delete) + map (create, update, toDetail, toSummary)
  • Offset pagination — page numbers, totalCount, totalPages, hasNext, hasPrev
  • Cursor pagination — O(log n) via MongoDB _id index, consistent under concurrent writes
  • ErrorOr throughout — no exceptions for business logic; failures propagate as structured errors
  • Summary/Detail response split — lightweight list DTOs vs full single-item DTOs
  • Global handler — every unhandled exception becomes RFC 7807 ProblemDetails with trace ID
  • /health/live and /health/ready with MongoDB probe, Docker health-check gated startup
  • Swagger with full XML documentation on every endpoint, model, parameter, and error
€35 See SPARK →
+ Keycloak auth
GUARD
GUARD Auth layer — all of SPARK + Keycloak JWT
  • JWT Bearer via OIDC discovery
  • Keycloak claim type mapping — non-standard claim names mapped to ASP.NET Core format
  • Two built-in policies: Authenticated (any valid JWT) and AdminOnly (admin realm role)
  • OAuth2 Authorization Code + PKCE in Swagger Authorize button
  • Pre-built realm export auto-imported at container startup — zero manual Keycloak configuration
  • Two test users ready (admin + user role) — log in via Swagger immediately after startup
  • 401/403 as RFC 7807 structured JSON — consistent error format, no HTML error pages
€45 See GUARD →
MongoDB + Redis without Keycloak
RAPID
RAPID Cache layer — MongoDB + Redis cache-aside
  • 11 hooks: 7 base (all kits) + 4 cache hooks (GetCacheKey, GetPagedCacheKey, GetCursorCacheKey, GetInvalidationTags)
  • Automatic cache-aside — BaseRepository checks Redis before every read, populates on miss
  • 3-level tag invalidation: automatic, tag-based, manual; union of old+new tags on update
  • FailOpen by default — Redis down = cache miss, not a 500; NullCacheService to disable with one flag
  • Two health checks (MongoDB + Redis) on /health/ready; Valkey 7.2 included
€45 See RAPID →
+ Redis cache-aside + Keycloak auth
FLICK
FLICK Cache + Auth — MongoDB + Keycloak JWT + Redis cache-aside
  • 4 cache hooks: GetCacheKey, GetPagedCacheKey, GetCursorCacheKey, GetInvalidationTags
  • Automatic cache-aside — BaseRepository checks Redis before every read, populates on miss
  • 3-level tag invalidation: automatic (all writes), tag-based (custom queries), manual (surgical single-key)
  • FailOpen by default — Redis down = cache miss, not a 500 error; NullCacheService to disable with one flag
  • JWT Bearer via OIDC discovery — Keycloak signing keys fetched automatically, no rotation needed
  • Role-based policies (Authenticated, AdminOnly), OAuth2 PKCE in Swagger, pre-built realm export
  • Two test users ready (admin + user), 401/403 as RFC 7807 JSON, Valkey 7.2 included
€55 See FLICK →
+ S3 file storage
UPLOADS
UPLOADS all of FLICK + S3 + 8 extra hooks
  • 19 hooks total — adds GetCacheTtl, GetNotFoundError, OnAfter* (post-success), OnFailed* (rollback)
  • GetCacheTtl — bound cache TTL per entity type; set shorter than presigned URL expiry to avoid stale links
  • GetNotFoundError — return domain-specific not-found errors instead of the generic fallback
  • OnAfterCreate/Update/Delete — post-success side effects: events, notifications, external cache invalidation
  • OnCreateFailed/UpdateFailed/DeleteFailed — rollback hooks: reverse any side effect if the DB write fails
  • Three S3 access modes: Public (direct URL), PresignedUrl (time-limited signed), Proxy (streamed through API)
  • Per-bucket configuration — different mode, TTL, and credentials per bucket if needed
  • Works with Garage, AWS S3 and any S3 api — only endpoint and credentials change
€65 See UPLOADS →
+ Hangfire background jobs
EMBER
EMBER Engine layer — all of UPLOADS + Hangfire background jobs
  • Fire-and-forget, delayed, and recurring CRON jobs via Hangfire
  • Three queue models (priority, dedicated, hybrid) — configured in appsettings.json, zero code changes
  • Hangfire dashboard at /jobs, MongoDB-backed persistence, configurable retry with exponential back-off
  • Pre-built example jobs: S3 orphan cleanup + product cache invalidation on critical queue
€75 See EMBER →

Two strategies.
Choose what fits.

Offset

Page-based

Classic numbered navigation. Returns totalCount, totalPages, hasNext, hasPrev.

12345 24
Showing 21–40 of 472 items
  • Jump to any page number
  • Total count always available
  • Ideal for back-office tables
  • Simple UX that users expect
Cursor

Cursor-based

O(log n) via MongoDB _id index. Consistent under concurrent writes. No degradation as the collection grows.

64f1a2b3c4d5e6f7item_01
64f1a2b3c4d5e6f8item_02
next → 64f1a2b3c4d5e6f9
  • Scales without performance loss
  • No duplicates under concurrent inserts
  • Forward and backward navigation
  • Ideal for feeds and large datasets

Override only what
your domain needs.

BaseRepository runs every CRUD operation. Override only the hooks that matter for your domain — 19 hooks validated against the real source code.

validate 01

OnValidateCreateAsync

Check uniqueness, business rules, and constraints before any write. Return Error to abort cleanly before the DB is touched.

returns ErrorOr<Success>
validate 02

OnValidateUpdateAsync

Validate the fully merged entity. Receives both the original and the enriched entity — compare them to enforce business rules.

returns ErrorOr<Success>
validate 03

OnValidateDeleteAsync

Guard against invalid deletions: check relations, enforce cascade rules, or block soft-deletes when conditions aren't met.

returns ErrorOr<Success>
map 04

OnMapCreateAsync

Enrich with server-side computed fields: slugs, tenant IDs, audit timestamps. These values must never come from the client.

returns ErrorOr<TEntity>
map 05

OnMapUpdateAsync

Recompute derived fields after an update: re-slug, recalculate denormalized fields. Receives original + request.

returns ErrorOr<TEntity>
map 06

OnMapToDetailAsync

Build the full single-item response. Compute derived fields, format values, load relations. Called by GetByIdAsync and CreateAsync.

returns ErrorOr<TDetail>
map 07

OnMapToSummaryAsync

Build the lightweight list response. Smaller payloads, cleaner contracts. Called by both pagination strategies (offset and cursor). Keep this lean — omit arrays and large nested objects.

returns ErrorOr<TSummary>
cache 08

GetCacheKey

Key for a single entity by ID. Default: "{type}:{id}". Scoped per repository — no conflicts across resources.

returns string
cache 09

GetPagedCacheKey

Key for an offset-paged list result. Default: "{type}:paged:p{page}:s{size}". Override for custom filter or tenant keys.

returns string
cache 10

GetCursorCacheKey

Key for a cursor-paged list result. Default includes cursor, page size, and direction. Override for tenant-scoped or filtered keys.

returns string
cache 11

GetInvalidationTags

Tags to wipe on any write. Default: entity-type + ID tag. Override to add category or tenant tags. Union of old+new applied on update to cover field changes.

returns IEnumerable<string>
cache 12

GetCacheTtl

Bound how long responses are cached. Return null for the global default. Set shorter than presigned URL expiry to avoid serving stale S3 links.

returns TimeSpan?
error 13

GetNotFoundError

Override to return a domain-specific not-found error (e.g. ProductErrors.NotFound(id)) instead of the generic one. Called on every null by-ID result.

returns Error
after 14

OnAfterCreateAsync

Runs after a successful insert + cache invalidation. Fire events, send notifications, invalidate external systems, or trigger background jobs.

returns Task
after 15

OnAfterUpdateAsync

Runs after a successful update + cache invalidation. Propagate change notifications, sync projections, or trigger search reindexing.

returns Task
after 16

OnAfterDeleteAsync

Runs after a confirmed delete + cache invalidation. Delete linked S3 objects, emit deletion events, or cascade side effects to other aggregates.

returns Task
rollback 17

OnCreateFailedAsync

Called when the DB insert fails after OnMapCreateAsync already ran. Roll back side effects — e.g. delete an S3 object that was just uploaded.

returns Task
rollback 18

OnUpdateFailedAsync

Called when the DB replace fails. Roll back any side effects performed during OnMapUpdateAsync before the database was touched.

returns Task
rollback 19

OnDeleteFailedAsync

Called when the DB delete fails after OnValidateDeleteAsync passed. Roll back any compensating actions triggered during validation before the delete ran.

returns Task

01–07 — all kits (SPARK, GUARD, RAPID, FLICK, UPLOADS, EMBER)  ·  08–11 — Redis kits (RAPID / FLICK / UPLOADS / EMBER)  ·  12–19 — UPLOADS & EMBER

The foundation is never
an afterthought.

01

BaseRepository — 19 hooks

A generic typed repository that handles all CRUD. Override only what your domain needs — most of the hooks return ErrorOr<T> so any failure aborts cleanly before the database is touched. 19 hooks validated against the real source code.

OnValidateCreateAsync OnMapCreateAsync OnMapToDetailAsync OnMapToSummaryAsync OnValidateUpdateAsync OnMapUpdateAsync OnValidateDeleteAsync GetCacheKey GetPagedCacheKey GetCursorCacheKey GetInvalidationTags GetCacheTtl OnAfterCreateAsync OnAfterUpdateAsync OnAfterDeleteAsync OnCreateFailedAsync OnUpdateFailedAsync OnDeleteFailedAsync GetNotFoundError
02

ErrorOr throughout

No exceptions for business logic. Every operation returns ErrorOr<T> — errors propagate to the global handler and become RFC 7807 ProblemDetails. No stack traces leaked to the client.

03

Two pagination strategies

Offset (page numbers, total count) for back-office UIs. Cursor (O(log n) via MongoDB _id index) for feeds and large collections. Consistent under concurrent writes, no degradation.

🐳

Docker Compose

One docker compose up --build starts everything. Health-check gated startup — API waits for every dependency before accepting requests.

❤️

Health checks

/health/live and /health/ready out of the box. Each dependency checked independently so failures are actionable.

📖

Swagger + XML docs

Every endpoint, model, and error documented with XML comments wired into Swagger UI. Open /swagger and everything is already there.