Kanject Core

Infrastructure,
Simplified.

Twelve focused .NET libraries that wrap AWS in clean, source-generated C# — every layer of a production service, from data to scheduling.

Runs in your own AWS account. You pay AWS directly — Kanject is a framework license, not a hosting bill.
Kanject.Core.NoSqlDatabaseNoSQL Data
var order = await orders.FindOrderByCustomerAsync(id);
order.Status = OrderStatus.Shipped;
await orders.UpdateAsync(order);
// Keys, GSIs, marshalling — derived from your POCOs.

Twelve libraries. One suite. Your AWS.

NoSQL Data
NoSqlDatabase
Kanject.Core.NoSqlDatabase

Type-safe NoSQL across DynamoDB, ScyllaDB, and Amazon Keyspaces — one [Repository] shape, three engines.

Learn more →
SQL Data
SqlDatabase
Kanject.Core.SqlDatabase

Relational sibling with an Aurora DSQL provider. Same [Repository] ergonomics as NoSqlDatabase.

Learn more →
Caching
CacheDb
Kanject.Core.CacheDb

Cache abstraction over DynamoDB, S3 Express, or in-memory — typed values, absolute expiry, namespaced keys.

Learn more →
File Storage
FileRepository
Kanject.Core.FileRepository

S3 wrapper with content-type detection, presigned URLs, and access levels.

Learn more →
Messaging Free
Queue
Kanject.Core.Queue

SQS wrapper — typed messages via IQueueManager, [QueueConsumer] batch handlers, retries, and automatic DLQ.

Learn more →
Compute
CloudFunction
Kanject.Core.CloudFunction

[CloudFunctionHost] source-generated Lambda host — DI, config source, and cold-start reuse wired for you.

Learn more →
Web API Free
Api
Kanject.Core.Api

ASP.NET Core baseline — BaseController Response<T> envelope, exception middleware, x-tenant-id resolution.

Learn more →
HTTP Integration
Adapter
Kanject.Core.Adapter

Typed adapters for outbound HTTP APIs — auth, retries, and source-generated endpoints.

Learn more →
QR Codes
Qr
Kanject.Core.Qr

First-party QR encoder with styled SVG/PNG rendering and a scannability verifier. AOT-clean.

Learn more →
Observability
Logs
Kanject.Core.Logs

A queryable, DynamoDB-backed log store — write records into named groups, read them back by text and time.

Learn more →
Scheduling
Recurring
Kanject.Core.Recurring

[Recurring(rate, unit)] on a method — a generated, drift-corrected recurring runner. Lambda, console, or hosted.

Learn more →
Batch / ETL
EtlTaskManager
Kanject.Core.EtlTaskManager

In-process Extract → Transform → Load for bounded imports and migrations. CSV, JSON, DynamoDB extractors.

Learn more →

Free Api & Queue are free under the Community license — individuals, open source, education, and companies under $250K.

Build with the same AWS services that run Airbnb, Nike, Zoom — and more.

Every Kanject Core library wraps a battle-tested AWS service running in production at the world's largest engineering teams. We give you the clean C# API. The infrastructure underneath is the same one those teams trust.

Same battle-tested infrastructure. Cleaner API. Faster ship.
Before & After

Stop writing boilerplate. Start shipping.

The same DynamoDB query — on the left, raw AWS SDK with manual credential wiring, expression attributes, and dictionary marshalling. On the right, idiomatic C# with Kanject.Core.NoSqlDatabase. Drag to compare.

60+
Lines eliminated
1
Line to register
0
Config files
Kanject.Core· clean, typed, testable
csharp
using Demo.Catalog.Data;

public class ProductService(ProductRepository products)
{
    public Task<IList<ProductEntity>> GetBySellerAsync(Guid sellerId)
        => products.FindSellerProductAsync(sellerId);

    public Task CreateAsync(ProductEntity product)
        => products.InsertAsync(product);
}

// The generated repository composes keys, queries Gsi1Index,
// marshals attributes, handles retries, and joins the unit of work.
AWS SDK· verbose, error-prone
csharp
using Amazon;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

var credentials = new BasicAWSCredentials(
    Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID"),
    Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY"));

var client = new AmazonDynamoDBClient(credentials,
    new AmazonDynamoDBConfig { RegionEndpoint = RegionEndpoint.EUWest1 });

// Query products by seller through a GSI
var queryRequest = new QueryRequest
{
    TableName = "products",
    IndexName = "Gsi1Index",
    KeyConditionExpression = "gsi1pk = :pk",
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>
    {
        { ":pk", new AttributeValue { S = "Seller#7b8b9a42-57de-4d97-b68d-762ee9c65c9a#Products" } },
    },
    Limit = 20,
};

var response = await client.QueryAsync(queryRequest);
var products = new List<Product>();
foreach (var item in response.Items)
{
    products.Add(new Product
    {
        Id          = item["id"].S,
        SellerId    = item["sellerId"].S,
        ProductName = item["productName"].S,
        Price       = decimal.Parse(item["price"].N),
    });
}

// Write a new product (manual marshalling)
await client.PutItemAsync(new PutItemRequest
{
    TableName = "products",
    Item = new Dictionary<string, AttributeValue>
    {
        { "pk",          new AttributeValue { S = "Products#f38d8d5b-b7be-4a7b-a5d5-bd2e70665b8f" } },
        { "sk",          new AttributeValue { S = "Info#7b8b9a42-57de-4d97-b68d-762ee9c65c9a" } },
        { "gsi1pk",      new AttributeValue { S = "Seller#7b8b9a42-57de-4d97-b68d-762ee9c65c9a#Products" } },
        { "gsi1sk",      new AttributeValue { S = "ProductInfo#f38d8d5b-b7be-4a7b-a5d5-bd2e70665b8f" } },
        { "id",          new AttributeValue { S = "f38d8d5b-b7be-4a7b-a5d5-bd2e70665b8f" } },
        { "sellerId",    new AttributeValue { S = "7b8b9a42-57de-4d97-b68d-762ee9c65c9a" } },
        { "productName", new AttributeValue { S = "Canvas tote" } },
        { "price",       new AttributeValue { N = "42.00" } },
    },
});
AWS SDKdrag to compareKanject.Core
Source Generators & Analyzers

You write this. We generate that.

Kanject.Core ships with Roslyn source generators and analyzers that turn a handful of attributes into a full, type-safe repository layer — compiled at build time. No reflection, no runtime surprises, no wrong-way-to-hold-it.

csharp
// <auto-generated> by Kanject DynamoDB Source Generator
#nullable enable
using System.Runtime.CompilerServices;
using Kanject.Core.Api.Abstractions.Models;
using Kanject.Core.NoSqlDatabase.Provider.DynamoDb.Abstractions.Extensions;
using Kanject.Core.NoSqlDatabase.Provider.DynamoDb.Abstractions.Interfaces;
using Kanject.Core.NoSqlDatabase.Provider.DynamoDb.Abstractions.Models;
using Kanject.Core.NoSqlDatabase.Provider.DynamoDbV2;
using Demo.Marketplace.Data.DbContexts;
using Demo.Marketplace.Data.Entities.SellerSettings;

namespace Demo.Marketplace.Data.Repositories;

public record struct SellerSettingRepositoryItemCollection(
    SellerSettingEntity? SellerSetting,
    SellerBundleDiscountSettingEntity? SellerBundleDiscountSetting);

public enum SellerSettingRepositoryItemCollectionType
{
    SellerSetting = 0,
    SellerBundleDiscountSetting = 1,
}

public partial class SellerSettingRepository
    : Repository<SellerSettingEntity>
{
    public SellerSettingRepository() {}

    public SellerSettingRepository(MarketplaceDbContext dbContext)
        : base(dbContext)
    {
        SetUnitOfWork(new UnitOfWork(dbContext));
    }

    protected QueryConfig QueryConfigInstance
    {
        get
        {
            var queryConfig = new QueryConfig { TableName = CurrentTableName };
            if (DbContext is not IDynamoDbContext dbContext)
                return queryConfig;

            if (dbContext.ModelBuilder?.PartitionKey is not null)
                queryConfig.AddPartitionKey(dbContext.ModelBuilder.PartitionKey);
            if (dbContext.ModelBuilder?.SortKey is not null)
                queryConfig.AddSortKey(dbContext.ModelBuilder.SortKey);

            return queryConfig;
        }
    }

    public void BeginTransaction() => UnitOfWork.BeginTransaction();

    public Task CommitAsync(CancellationToken? cancellationToken = null)
        => UnitOfWork.TransactionExpressions.Count > 0
            ? UnitOfWork.CommitAsync(cancellationToken)
            : Task.CompletedTask;

    private SellerSettingRepositorySellerBundleDiscountSettingEntityRepository?
        _sellerBundleDiscountSetting;

    public SellerSettingRepositorySellerBundleDiscountSettingEntityRepository
        SellerBundleDiscountSetting
    {
        get
        {
            _sellerBundleDiscountSetting ??= DbContext is not null
                ? new SellerSettingRepositorySellerBundleDiscountSettingEntityRepository(
                    Unsafe.As<MarketplaceDbContext>(DbContext))
                : new SellerSettingRepositorySellerBundleDiscountSettingEntityRepository();

            if (UnitOfWork is not null)
                _sellerBundleDiscountSetting.SetUnitOfWork(UnitOfWork);

            return _sellerBundleDiscountSetting;
        }
    }

    public Task<SellerSettingEntity?> FindSellerSettingAsync(
        Guid sellerUserId,
        bool isConsistentRead = true,
        QueryConfig? queryConfig = null)
    {
        queryConfig ??= QueryConfigInstance;
        queryConfig.AddPartitionKeyValue(
            SellerSettingEntityKeys.ComposeSellerSettingPartitionKey(sellerUserId));
        queryConfig.AddSortKeyValue(
            DbFunc.Equals(SellerSettingEntityKeys.ComposeSellerSettingSortKey()));

        return GetSingleAsync(
            queryConfig.ReturnEventualConsistentData(!isConsistentRead));
    }

    // + 1,100 lines: typed overloads, update/insert helpers,
    // entity-repository methods, key composers, checks, and DI registration.
}
Compile-time safe
Analyzers flag missing DbContext, bad entity types, and wrong versions before you run a single test.
Zero reflection
Every dependency is wired at build time. Cold-start is instant; there’s no runtime scanning.
Harder to misuse
The generated API only exposes correct shapes — you literally can’t call it the wrong way.
Compile-time docs · AI-ready

Every build emits a manual.

Every Kanject Core library writes a comprehensive Markdown spec at compile time — generated repositories, key templates, indexes, queues, event topics, cache contexts. The same source-generator pass that emits typed C# also emits the README, in full. Drop the file straight into your AI assistant for instant, accurate codebase context.

csharp
using Amazon.DynamoDBv2.DataModel;using Kanject.Core.NoSqlDatabase.Provider.DynamoDb.Annotations.Attributes;using Demo.Marketplace.Data.DbContexts;[DbContext][EnableRecordLifeTimeSupport]public partial class MarketplaceDbContext;public record SellerSettingEntity : AbstractBaseEntity{    [KeyTemplate("SellerSettings#{SellerUserId}")]    [DynamoDBHashKey("pk")]    public override string PartitionKey { get; set; } = string.Empty;    [KeyTemplate("Info")]    [DynamoDBRangeKey("sk")]    public override string SortKey { get; set; } = string.Empty;    [DynamoDBProperty] public Guid SellerUserId { get; set; }    [DynamoDBProperty] public HolidayModeStatus HolidayModeStatus { get; set; }}[Repository(Entity = typeof(SellerSettingEntity), Version = 2)][DbContext(typeof(MarketplaceDbContext))][EntityRepository(typeof(SellerBundleDiscountSettingEntity),    IsMultipleCollectionItem = false)]public partial class SellerSettingRepository;
Demo.Marketplace.Data.dbschema.md 352 KB

Demo.Marketplace.Data — DynamoDB Schema Reference

Auto-generated by Kanject DynamoDB Source Generator. Do not edit manually.
Database Contexts1
Repositories13
Global Secondary Indexes1
Expiring Records3
Embedded Repositories7
Unique Entities22
Key Templates46
Kanject Indexes24
  1. Quick Overview
  2. Core Concepts & Glossary
  3. Common Tasks
  4. Constraints & Invariants
  5. Do / Don't Guidance
  6. Generated vs. Handwritten Code
  7. Single Table Key Design
  8. Repositories 13
  9. Global Secondary Indexes
  10. Expiring Records
  11. Capacity & Throughput
  12. WCU/RCU Cost per Access Pattern
  13. CloudWatch Alarm Recommendations
  14. Security Posture & IAM Actions
  15. Method Quick Reference
  16. … 13 more sections
352 KB
Per assembly
Example: Demo.Marketplace.Data
28 sections
Catalogued
Repos · indexes · keys · capacity · IAM
13 repos
Generated surface
Methods mapped to native DynamoDB operations
1 file
Full AI context
Drop into Claude, Cursor, Copilot, ChatGPT

Your first package is free. The suite is one license away.

Api and the base Queue are Community packages — pull them from public NuGet and start building today. The paid libraries ship from a private feed: license the suite, and one sign-in with the free CLI connects it for your machine, your teammates, and your CI. Deploying with the CLI stays entirely optional.

Ship faster, with fewer mistakes.

Core gives you the primitives to build all of this yourself. Kanject BaaS is optional — auth, wallet, notifications, analytics and more, pre-assembled and hardened in your own AWS, for when you'd rather move faster than rebuild a ledger or an identity layer from scratch.

FileServer Forms beta Identity Identity.Server beta Insights InstantMessaging NotificationHub EventHub Wallet

See your data layer, visually.

Paste your annotated POCOs and DynoStudio derives the tables, the indexes, and the typed query functions — then lets you browse and query without leaving the studio. The same surface drives every Kanject demo call.

Kanject DynoStudio us-east-1
FileEditViewSchemaQueryToolsHelp
ItemsSchemaModelQueryIndexes
No connection yet
Pick an AWS profile, or paste an annotated C# schema to start exploring without a connection.
Connect to AWSPaste SchemaUse LocalStack
Ready to ship?

Simplify your cloud
journey today.

Join forward-thinking developers and businesses who trust Kanject to eliminate cloud complexity and accelerate innovation.