Skip to content

Infrastructure Intents

Infrastructure intents let you declare what resources your application needs without specifying provider-specific details. VentureKit translates intents into AWS resources (RDS, S3, SQS, ElastiCache, etc.) at deploy time.

Traditional IaC (Infrastructure as Code) requires you to know AWS service names, instance types, and configuration parameters. Intents abstract this:

  • CDK updates only require updating @venturekit/infra — consumer code stays the same
  • Stable API for consuming projects — intents don’t change when CDK does
  • Simplified configuration — no need to know AWS instance types

Define what resources exist once in vk.config.ts (names, types, purposes). Then override sizing and behavior per environment in config/dev.ts and config/prod.ts.

import { defineVenture } from '@venturekit/infra';
import { base } from './config/base';
import { security } from './config/security';
import { dev } from './config/dev';
import { prod } from './config/prod';
export default defineVenture({
base,
security,
databases: [
{ id: 'main', type: 'postgres', name: 'app' },
],
storage: [
{ id: 'uploads', purpose: 'uploads' },
],
queues: [
{ id: 'jobs', type: 'standard' },
],
envs: { dev, prod },
});

Each env config overrides only what differs. Items are matched by id and shallow-merged with the shared definition:

config/dev.ts
import type { EnvConfigInput } from '@venturekit/core';
export const dev: EnvConfigInput = {
preset: 'free',
databases: [
{ id: 'main', size: 'small' },
],
};
config/prod.ts
import type { EnvConfigInput } from '@venturekit/core';
export const prod: EnvConfigInput = {
preset: 'medium',
databases: [
{ id: 'main', size: 'large', highAvailability: true, backups: true },
],
storage: [
{ id: 'uploads', cdn: true },
],
queues: [
{ id: 'jobs', deadLetterQueue: true },
],
};

At deploy time, VentureKit merges the shared definitions with the active environment’s overrides and provisions the corresponding AWS resources.

{
id: 'main-db',
type: 'postgres', // 'postgres' | 'mysql'
size: 'small', // 'small' | 'medium' | 'large' | 'xlarge'
name: 'app_main',
highAvailability: true, // Multi-AZ
backups: true,
backupRetentionDays: 7,
encrypted: true,
performanceInsights: true,
}
{
id: 'uploads',
purpose: 'uploads', // 'uploads' | 'assets' | 'backups' | 'logs'
cdn: true, // Enable CloudFront
cdnDomain: 'cdn.example.com',
versioned: true,
corsOrigins: ['https://app.example.com'],
}
{
id: 'user-pool',
signInWith: ['email', 'phone'],
allowSignUp: true,
mfa: 'optional', // 'off' | 'optional' | 'required'
passwordStrength: 'strong', // 'standard' | 'strong'
scopes: [{ name: 'read', description: 'Read access' }],
clients: [{ name: 'web-app', scopes: ['read', 'write'] }],
}
{
id: 'email-queue',
type: 'standard', // 'standard' | 'fifo'
deadLetterQueue: true,
retentionDays: 7,
visibilityTimeoutSeconds: 60,
}
{
id: 'session-cache',
type: 'redis', // 'redis' | 'memcached'
size: 'small', // 'small' | 'medium' | 'large' | 'xlarge'
clustered: false,
}
// Rate-based
{
id: 'cleanup-job',
handler: 'src/jobs/cleanup.handler',
schedule: { rate: '1 hour' }, // "5 minutes", "1 hour", "1 day"
enabled: true,
}
// Cron-based
{
id: 'daily-report',
handler: 'src/jobs/report.handler',
schedule: { cron: '0 8 * * ? *' }, // 8:00 AM UTC daily
enabled: true,
}

Declares the application’s transactional-messaging surface (email / WhatsApp / SMS / push). VentureKit provisions an SES identity + configuration set, a bounce/complaint SNS topic, an outbox table in your Postgres database, and a dispatcher cron — your handlers just call notify.send(...).

{
id: 'main',
channels: ['email', 'whatsapp'], // 'email' | 'whatsapp' | 'sms' | 'push'
defaultFrom: 'no-reply@app.example.com',
domain: 'app.example.com', // SES DomainIdentity with DKIM signing
hostedZoneId: 'Z123ABCEXAMPLE', // auto-publish DKIM CNAMEs in Route 53
tracking: 'postgres', // 'postgres' (default) | 'none'
dispatchRateMinutes: 1, // dispatcher poll rate
dispatchBatchSize: 50, // notifications claimed per invocation
whatsapp: {
phoneNumberId: '1234567890', // Meta Cloud API Phone Number ID
apiVersion: 'v21.0',
},
}

Most projects need exactly one notify intent (id: 'main'). The WhatsApp access token is stored in a Secrets Manager secret created by the stack — populate it after the first deploy.

SizeDB InstanceCache Node
smalldb.t3.smallcache.t3.small
mediumdb.r6g.largecache.r6g.large
largedb.r6g.xlargecache.r6g.xlarge
xlargedb.r6g.2xlargecache.r6g.2xlarge

After infrastructure is provisioned, outputs are available in route handlers via ctx.intentOutputs:

import { handler } from '@venturekit/runtime';
import type { IntentOutputs } from '@venturekit/core';
export const main = handler(async (_body, ctx, logger) => {
const outputs = ctx.intentOutputs as IntentOutputs;
// Database
const dbEndpoint = outputs.databases['main-db'].endpoint;
const dbPort = outputs.databases['main-db'].port;
const dbSecretArn = outputs.databases['main-db'].secretArn;
// Storage
const bucketName = outputs.storage['uploads'].bucketName;
const cdnUrl = outputs.storage['uploads'].cdnUrl;
// Queue
const queueUrl = outputs.queues['email-queue'].queueUrl;
// Cache
const cacheEndpoint = outputs.caches['session-cache'].endpoint;
// Auth
const userPoolId = outputs.auth['user-pool'].userPoolId;
// Notify (SES + dispatcher)
const sesConfigSet = outputs.notify['main'].configurationSetName;
const bounceTopicArn = outputs.notify['main'].eventsTopicArn;
return { dbEndpoint, bucketName, queueUrl };
});

Intent outputs are serialized into the VENTURE_INTENT_OUTPUTS Lambda environment variable and hydrated automatically into ctx.intentOutputs at runtime.