Infrastructure,
Simplified.
Twelve focused .NET libraries — distributed via private NuGet — that wrap the AWS surface in clean, expressive C# APIs. Data, messaging, compute, files, secrets, scheduling — every layer of a production .NET service, source-generated.
Latest: NoSqlDatabase now targets ScyllaDB and Keyspaces alongside DynamoDB · new SqlDatabase sibling joins it in beta on Aurora DSQL.
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.
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.
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.
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.
// <auto-generated> by Kanject.SourceGen — do not edit </auto-generated>
// Generated at build time from [Repository], [EntityRepository<T>],
// [EmbedRepository<T>] and [DbContext] attributes.
namespace Kanject.Insights.Provider.Aws.Abstractions.Repositories;
public partial class CohortInsightRepository : RepositoryBase<CohortInsightEntity>
{
private readonly KanjectInsightDbContext _dbContext;
private readonly IEntityRepository<CohortInsightDefinitionEntity> _definitions;
private readonly IEntityRepository<CohortActivityInsightDefinitionEntity> _activityDefs;
private readonly IEntityRepository<List<CohortInsightMetricEntity>> _metrics;
private readonly IEntityRepository<List<CohortInsightFilterEntity>> _filters;
private readonly IEntityRepository<List<CohortInsightAlertRuleEntity>> _alertRules;
private readonly IEntityRepository<List<CohortInsightAlertStateEntity>> _alertStates;
private readonly CohortSnapshotRepository _snapshots;
public CohortInsightRepository(
KanjectInsightDbContext dbContext,
IEntityRepository<CohortInsightDefinitionEntity> definitions,
IEntityRepository<CohortActivityInsightDefinitionEntity> activityDefs,
IEntityRepository<List<CohortInsightMetricEntity>> metrics,
IEntityRepository<List<CohortInsightFilterEntity>> filters,
IEntityRepository<List<CohortInsightAlertRuleEntity>> alertRules,
IEntityRepository<List<CohortInsightAlertStateEntity>> alertStates,
CohortSnapshotRepository snapshots)
: base(dbContext, version: 2)
{
_dbContext = dbContext;
_definitions = definitions;
_activityDefs = activityDefs;
_metrics = metrics;
_filters = filters;
_alertRules = alertRules;
_alertStates = alertStates;
_snapshots = snapshots;
}
// + 340 lines: typed getters, migrations, health checks,
// DI registration, batch helpers, analyzer hints…
}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.
using Kanject.Core.NoSqlDatabase.Provider.DynamoDb.Annotations.Attributes;
[Repository(Entity = typeof(CountryEntity), Version = 2)]
[DbContext(typeof(ConfigurationDbContext))]
[EntityRepository<CountryDialingCodeEntity>]
[EntityRepository<List<CountrySeasonEntity>>]
[EntityRepository<List<CountrySetupEntity>>]
[EmbedRepository<PayoutProviderRepository>]
[EmbedRepository<ShippingProviderRepository>]
[DynamoDbGsi(name: "country-by-iso", pk: "iso2", sk: "name")]
public partial class CountryRepository;
// 11 lines. The source generator does the rest… Trifted.Configuration.Data — DynamoDB Schema Reference
| Database Contexts | 1 |
| Repositories | 19 |
| Global Secondary Indexes | 2 |
| Item Collections | 1 |
| Embedded Repositories | 7 |
| Unique Entities | 29 |
| Key Templates | 84 |
| Kanject Indexes | 26 |
- Quick Overview
- Core Concepts & Glossary
- Common Tasks
- Constraints & Invariants
- Single-Table Key Design
- Database Contexts
- Repositories 19
- Global Secondary Indexes
- Capacity & Throughput
- Hot Partition Risk Analysis
- WCU/RCU Cost per Access Pattern
- CloudWatch Alarm Recommendations
- Security Posture & IAM Actions
- Method Quick Reference
- … 13 more sections
Kanject.Core.NoSqlDatabase
One [Repository] shape, three engines. Pick AddDynamoNoSqlDatabase(), AddScyllaNoSqlDatabase() or AddKeyspacesNoSqlDatabase() — connection pooling, retries, and type marshalling are handled by the provider so your code never knows the difference.
// One repository, three engines. Same [Repository] interfaces compile against
// DynamoDB, ScyllaDB, or Amazon Keyspaces — pick the provider extension you
// want at registration time and the rest of your code never knows the
// difference.
using Kanject.Core.NoSqlDatabase.Provider.DynamoDbV2.Extensions;
// or: Kanject.Core.NoSqlDatabase.Provider.Scylla.Extensions;
// or: Kanject.Core.NoSqlDatabase.Provider.Keyspaces.Extensions;
builder.Services.AddDynamoNoSqlDatabase(options =>
{
options.Namespace = appSettings.DatabaseNamespace;
options.AccessKey = appSettings.AwsAccessKeyId;
options.SecretKey = appSettings.AwsAccessSecretKey;
options.AwsRegion = appSettings.AwsRegion;
#if DEBUG
options.EnableDbMigration();
options.EnableDebugLogging();
#endif
});
// Inject anywhere — self-documenting repository pattern. The query below
// runs unchanged on DynamoDB, ScyllaDB, or Keyspaces.
public class ProductRepository(INoSqlDatabase db)
{
public Task<IReadOnlyList<Product>> GetByCategoryAsync(string category)
=> db.QueryAsync<Product>(
partitionKey: $"category#{category}",
sortKeyPrefix: "product#",
limit: 20);
} Kanject.Core.SqlDatabase — Aurora DSQL · beta
The relational sibling to NoSqlDatabase. Same options pattern, same source-generated [Repository] interfaces — running on Amazon Aurora DSQL. In beta: APIs are stable, but expect provider-level options to land in the next minor release.
using Kanject.Core.SqlDatabase.Provider.AuroraDsql.Extensions;
// Beta — same options pattern, same self-documenting repositories.
builder.Services.AddAuroraDsqlSqlDatabase(options =>
{
options.ClusterEndpoint = appSettings.AuroraDsqlEndpoint;
options.AwsRegion = appSettings.AwsRegion;
options.Namespace = appSettings.DatabaseNamespace;
});
[Repository(table: "Orders")]
public partial interface IOrderRepository : IRepository<Order>
{
[Query(by: nameof(Order.CustomerId))]
Task<IReadOnlyList<Order>> ListByCustomerAsync(Guid customerId);
}
public record Order
{
[PrimaryKey] public Guid Id { get; init; }
[Indexed("ByCustomer")] public Guid CustomerId { get; init; }
public decimal Total { get; init; }
public DateTimeOffset PlacedAt { get; init; }
} Kanject.Core.Queue + Logs
Async-first SQS wrapper with built-in dead-letter queue support and retry logic. Pair with Kanject.Core.Logs for structured, correlated log output — all in a few lines of C#.
using Kanject.Core.Queue.Extensions;
using Kanject.Core.Logs.Extensions;
builder.Services.AddSqsQueue(options =>
{
options.AwsRegion = appSettings.AwsRegion;
options.DeadLetterQueueEnabled = true;
options.MaxRetries = 3;
});
builder.Services.AddKanjectLogs();
// Inject — clean async API, structured logs correlated by request
public class OrderService(IQueueService queue, ILogger<OrderService> log)
{
public async Task PlaceAsync(Order order)
{
await queue.SendAsync("order-processing", order);
log.LogInformation("Order queued {OrderId}", order.Id);
}
} Kanject.Core.FileRepository + Secrets
File storage done right — automatic content-type detection, presigned URLs, and access control. Pair with Kanject.Core.Secrets for safe AWS Secrets Manager retrieval in any environment.
using Kanject.Core.FileRepository.Provider.AwsS3.Extensions;
using Kanject.Core.Secrets.Extensions;
builder.Services.AddAwsS3FileRepository(options =>
{
options.BucketName = fileSettings.BucketName;
options.Region = appSettings.AwsRegion;
options.FileServerBaseUrl = fileSettings.FileServerBaseUrl;
options.ResourceTypeDefinitions.AddResourceTypeDefinitions();
});
builder.AddAwsSystemManagerParameterStore(); // zero-config secrets
// Inject both — presigned URLs, content-type auto-detection
public class AvatarService(IFileRepository files, ISecretsProvider secrets)
{
public Task<string> UploadAsync(Stream stream, Guid userId)
=> files.UploadAsync(stream, $"avatars/{userId}.png", isPublic: true);
} From the team — about this module.
Parallel.ForEachAsync wasn't enough. So we built our own.
The four things every batched-I/O workload needs — scoped DI, retry policy, per-partition timeout, and partial-batch acknowledgement — none of which the BCL gives you in one place. Here's why we shipped Kanject.Core.Parallel.
How we ship source generators that survive refactors
Lessons from two years of building Roslyn generators that don't silently break when downstream code moves.
Cadence belongs on the method, not in startup
Why we built drift-corrected, attribute-driven recurring tasks with three call-site overloads — and why we don't think you should reach for Timer, PeriodicTimer, or BackgroundService directly anymore.
Simplify your cloud
journey today.
Join forward-thinking developers and businesses who trust Kanject to eliminate cloud complexity and accelerate innovation.