← All posts

Deploying Lambda services into customer AWS accounts

The CloudFormation patterns we use to deploy the same .NET service into dozens of isolated customer environments — without managing them.

Multi-tenant SaaS is the default model for almost every B2B product. Pool everyone into one database, isolate by tenant ID, scale the runtime once.

We don’t ship that.

Every Kanject deploy lands inside the customer’s own AWS account. Their data, their bucket, their IAM policies. We never touch it. The same .NET service ships to dozens of isolated environments, and we operate exactly zero of them.

Here’s how we do it without losing our minds.

The architecture in one paragraph

Every Kanject module — Identity, Wallet, NotificationHub, the lot — ships as a NuGet package and a CloudFormation template. The customer runs kanject deploy (or wires the template into their own CodePipeline). The template provisions every AWS resource the module needs: DynamoDB tables, S3 buckets, Cognito user pools, SQS queues, Lambda functions. All inside their account. All under their IAM.

We don’t have access. We don’t have credentials. We don’t have a control plane. The customer owns the keys.

What this changes for the customer

The pitch is simple: data residency stops being a quarterly meeting. Compliance stops being a paperwork exercise. The auditor walks into your AWS account, sees Cognito user pools and DynamoDB tables, and writes “standard AWS managed services” in the report. Done.

The customer also gets the AWS-native tooling for free. CloudWatch metrics already exist. CloudTrail audit logs already exist. AWS Backup already works. We didn’t have to ship any of that — AWS did.

What this changes for us

We don’t run anything. There’s no Kanject control plane. There’s no Kanject database that holds anyone’s data. There’s no Kanject endpoint that can leak.

This means we don’t have to be SOC 2 certified to sell to a SOC 2 customer — the customer is, because their AWS account is. We don’t have to negotiate DPAs as if we’re a data processor — we’re not, because the data never leaves their account.

It also means we can’t get hacked into a customer’s data. We literally don’t have it.

The hard part

The hard part is deployment ergonomics. CloudFormation is verbose. CDK is better but forces a build step in the customer’s CI. Terraform is great but adds a third tool to the customer’s stack.

Our answer: ship templates, not scripts. Every module’s CloudFormation template is hand-tuned for the smallest possible blast radius and the cleanest IAM policy. The customer can read it. The customer can modify it. The customer can copy it into their own infrastructure-as-code repo.

We give them the recipe. They own the kitchen.

Trade-offs we accept

This model has costs. Customer success is harder — we can’t see their logs unless they share them. Debugging is harder — we can’t aws cli into their account. Onboarding is slower — they have to actually deploy infrastructure before they can sign in.

We accept all of those, because the alternative — running a multi-tenant SaaS that holds every customer’s data — is the model we don’t want to be in.

If you’re evaluating Kanject and the “deploy to your AWS” model is new to you, the /baas overview walks through how each module fits together. If you’re a customer who already runs the platform and you want a deeper portability story, talk to us — we have a portability assessment doc that goes module by module.

More field notes from the team.

Architecture April 26, 2026

Building a serverless analytics engine that scales to zero

Most analytics products solve the dashboard latency problem with an always-on OLAP cluster. We solved the same problem differently — Lambda + DynamoDB + S3 Express + EventBridge in your AWS account. Here's the architecture brief.

Product April 22, 2026

Six analytics patterns. Zero SQL. Introducing Kanject Insights.

We shipped a click-to-insight engine that supports the six analytics patterns every product team needs — funnels, cohorts, correlations, and more — without writing a line of SQL.

Engineering April 15, 2026

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.