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.
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.
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.
// 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);
}
};// 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);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.
# 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.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.”
DynamoDB tables
The entities, commands and configs tables live in your account, single-table design, fully documented schema.
S3 buckets
Asset uploads, archives, backups. All in buckets you own, with lifecycle policies you configure.
Aurora Postgres
If provisioned, the relational projections remain queryable by any Postgres client. No vendor extensions, no proprietary SQL.
OpenSearch indices
Full-text and vector indices in AWS-managed OpenSearch, reachable by standard OpenSearch/Elasticsearch clients.
EventBridge archive
Ninety days of event history by default, extendable. Replayable into anything. Your audit trail, your ownership.
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.