Vol. VII · Functory Quarterly№ 001 · Edition 2026
I
Trust

You are never trapped.

A library of primitives, not a framework that owns your application.

This page documents the three mechanisms — in code — that keep it that way.

II
Sovereignty

Everything runs in your account.

No multi-tenant control plane. No proprietary hop in the data path.

Functory provisions resources with CDK and hands you the keys.

Functory data architectureApplication writes to DynamoDB. DynamoDB streams feed MSK Kafka, which acts as the change-data-capture backbone. Every downstream database — Aurora Postgres, OpenSearch, Neo4j, Neptune, Redis, or any additional datastore the customer provisions — consumes from Kafka. Everything runs inside the customer's own AWS account.Your AWS accountsingle VPC · IAM you control · billed directly by AWSApplicationScala/ZIO on EKS · REST · GraphQL · gRPCwritesDynamoDBsingle-table · source of truthstreams (CDC)MSK Kafkaevent backbone · every projection is a consumerfan-out →PGAurorarelationalOSOpenSearchfull-text + vectorN4Neo4jgraphNPNeptunegraph · managedRRediscache / sessions?Any databasevia custom cdc-sync
III
Mechanism 01

Custom Lambdas, same stack.

When the built-in primitives don't fit, write a Lambda. Functory provisions a bootstrapped customer CDK app next to its own sealed stack; your Lambdas, queues, and infrastructure live in that customer app and import the Functory stack's outputs — table ARNs, event log topics, IAM roles — as first-class references. No plugin framework, no SDK to learn, just CDK.

lambdas/enrich-reservation.ts
// A Lambda you write. Deployed alongside Functory, inside the same CDK
// stack, reading from the same DynamoDB table. Functory never sees the
// source — it's your code on your infrastructure.

import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import type { DynamoDBStreamHandler } from "aws-lambda";

const ddb = new DynamoDBClient({});
const TABLE = process.env.FUNCTORY_ENTITIES_TABLE!;

export const handler: DynamoDBStreamHandler = async (event) => {
  for (const record of event.Records) {
    if (record.eventName !== "INSERT") continue;
    const kind = record.dynamodb?.NewImage?.kind?.S;
    if (kind !== "Reservation") continue;

    // Your business logic. Anything. Enrich, dual-write, audit, route.
    await yourCrmClient.enqueue(record.dynamodb!.NewImage);
  }
};
customer-cdk/app.ts
// Your bootstrapped customer CDK app — provisioned alongside the
// Functory-owned CDK stack. Functory's stack is sealed (you don't edit it);
// your stack is yours, and it can read outputs from Functory's to plug into
// the same table, event bus, and IAM roles.

import { CustomerCdkApp } from "@functory/customer-cdk";
import { Function as Lambda, Runtime, Code } from "aws-cdk-lib/aws-lambda";

const app = new CustomerCdkApp("acme-prod-customer");
const functoryOutputs = app.importFunctoryOutputs(); // table ARNs, topics, roles

const enrich = new Lambda(app, "EnrichReservation", {
  runtime: Runtime.NODEJS_20_X,
  code: Code.fromAsset("lambdas/enrich-reservation"),
  handler: "index.handler",
  environment: {
    FUNCTORY_ENTITIES_TABLE: functoryOutputs.entitiesTable.tableName,
  },
});

functoryOutputs.entitiesTable.grantStreamRead(enrich);
IV
Mechanism 02

Direct database access.

Your DynamoDB table, your IAM. Query it with any AWS SDK, any CLI, any role you define. The same applies to every overflow database: Postgres, OpenSearch, Neo4j, Neptune, Redis — all standard, all yours.

Need a store we don't ship? Provision it in your customer CDK app and write a cdc-sync consumer that reads from the same event log topic the built-in projections read from. The set of downstream databases is open-ended — anything the event log can feed, you can hydrate.

$ aws dynamodb query
# Your AWS account. Your table. Your IAM. Functory has no role here.

aws dynamodb query \
  --table-name acme-prod-entities \
  --index-name kindStatus-fragments-gsi \
  --key-condition-expression "kindStatus = :ks" \
  --expression-attribute-values '{":ks":{"S":"Reservation#Confirmed"}}' \
  --profile acme-prod

# Same story for the overflow databases:
#   psql  postgres://acme-prod.cluster-xxx.amazonaws.com/entities
#   curl  https://search-acme-prod.es.amazonaws.com/reservations/_search
#   cypher-shell -a neo4j://acme-prod.compute.amazonaws.com -u neo4j
#   redis-cli -h acme-prod.cache.amazonaws.com
#
# No proprietary API in the middle. No usage meter. Just AWS.
V
Mechanism 03

Keep your data, keep walking.

If you decide Functory is no longer the right fit, here is a concrete list of what stays with you. There is no proprietary copy of your data anywhere else, because there is no “anywhere else.”

  • 01

    DynamoDB tables

    The entities, commands and configs tables live in your account, single-table design, fully documented schema.

  • 02

    S3 buckets

    Asset uploads, archives, backups. All in buckets you own, with lifecycle policies you configure.

  • 03

    Aurora Postgres

    If provisioned, the relational projections remain queryable by any Postgres client. No vendor extensions, no proprietary SQL.

  • 04

    OpenSearch indices

    Full-text and vector indices in AWS-managed OpenSearch, reachable by standard OpenSearch/Elasticsearch clients.

  • 05

    EventBridge archive

    Ninety days of event history by default, extendable. Replayable into anything. Your audit trail, your ownership.

  • 06

    Customer CDK app

    Your bootstrapped customer CDK lives in your repository, tracked in git, and keeps deploying with or without Functory. It owns the references to every resource your application depends on.

Coda

Not a framework you’re trapped in.
Primitives you’re free to leave.

Three mechanisms, one promise.

The platform stays out of your way until you need it, and steps aside the day you don’t.