Skip to content

mantle.config.ts Reference ​

Project configuration for Mantle, declared via defineConfig() from @j0nathan-ll0yd/core.

typescript
// mantle.config.ts
import { defineConfig } from "@j0nathan-ll0yd/core";

export default defineConfig({
  name: "my-api",
});

The CLI reads this file at build and deploy time. It does not affect Lambda runtime behavior.


Top-Level Options ​

OptionTypeRequiredDescription
namestringyesProject name. Used as prefix for Terraform resource naming.
databaseobject—Database provider config.
authobject—Auth provider config.
featuresobject—Feature flags for observability and resilience.
backendobject—Remote Terraform state backend (S3).
allowedStagesarray—Stages mantle deploy may target; any other --stage is hard-refused.
customVariablesarray—Additional Terraform variables appended to variables.tf.
storagearray—S3 storage buckets to provision.
eventbridgeobject—EventBridge custom bus configuration.
corsobject—CORS policy for API Gateway responses.
queuesarray—SQS queues to provision.
dynamodbarray—DynamoDB tables to provision.
websocketobject—WebSocket API Gateway configuration.
observabilityobject—ADOT and metrics configuration.
secretsobject—SOPS-encrypted secrets configuration.
snsobject—SNS topics and platform applications.
cloudfrontobject—CloudFront distribution fronting API Gateway.
authorizerobject—API Gateway custom authorizer cache settings.
layersarray—Custom Lambda layers.
containerRegistryobject—ECR container registry configuration (imageRetentionCount only).
ciobject—CI pipeline settings for mantle ci and workflow generation.
openapiobject—Extra schema sources for mantle generate openapi.
awsSdkAppIdstring—AWS SDK user-agent application identifier.

Database ​

typescript
database: {
  provider: "aurora-dsql";
}
OptionTypeDescription
provider'aurora-dsql' | 'aurora-serverless-v2' | 'neon'Database provider.

Backend (Terraform State) ​

typescript
backend: {
  s3: {
    bucket: 'my-tfstate',
    key: 'infra.tfstate',
    region: 'us-east-1',
  }
}
OptionTypeDescription
s3.bucketstringS3 bucket name.
s3.keystringState file key.
s3.regionstringBucket region.
s3.encryptbooleanEnable server-side encryption.
s3.dynamodbTablestringDynamoDB table name for state locking. Deprecated — prefer useLockfile.
s3.workspaceKeyPrefixstringKey prefix for Terraform workspaces.
s3.useLockfilebooleanS3-native state locking via conditional writes (OpenTofu 1.10+). Preferred over DynamoDB; defaults to true for new projects.

Allowed Stages (Deploy Guard) ​

typescript
allowedStages: ["staging"];

When set, mantle deploy --stage <stage> hard-errors for any stage not in the list — at stage-validation time, before any build, generate, or tofu invocation, so --dry-run is refused too and --yes does not bypass it. Unset means all stages are allowed. Use with a single shared state backend to prevent a wrong-stage deploy from renaming (destroy + recreate) every resource in the live stack.

Related: an apply whose initialized state lists zero addresses (empty local file or empty remote key — e.g. a stale checkout pointing at a pre-rename backend key) is refused when the account already has {stage}--prefixed Lambdas (override with --allow-empty-state for a genuine first bootstrap).


EventBridge ​

typescript
eventbridge: {
  bus: 'MyBus',
  sqsTargets: [
    {
      detailType: 'OrderCreated',
      queue: 'OrderQueue',
    }
  ]
}
OptionTypeDescription
busstringCustom event bus name.
sqsTargetsarrayEventBridge rules that route events to SQS queues.
sqsTargets[].detailTypestringEventBridge detail-type to match.
sqsTargets[].queuestringQueue name (must match an entry in queues).
sqsTargets[].inputTransformerobjectReshape event before delivery. Has inputPaths and inputTemplate.

Storage (S3) ​

typescript
storage: [{ name: "assets", cloudfront: true, intelligentTiering: true }];
OptionTypeDefaultDescription
namestring—Bucket logical name.
bucketNameOverridestring—Full bucket name as Terraform expression, bypasses name prefix.
cloudfrontbooleanfalseProvision a CloudFront distribution.
cloudfrontPriceClassstring—CloudFront price class.
corsOriginsstring[]—CORS allowed origins for the bucket.
corsMethodsstring[]—CORS allowed methods.
intelligentTieringbooleanfalseEnable S3 Intelligent-Tiering.
versioningbooleanfalseEnable object versioning.
assetsstring[]—Static asset keys to upload. Source path: static/{key} at project root.

Queues (SQS) ​

typescript
queues: [{ name: "OrderQueue", visibilityTimeoutSeconds: 300 }];
OptionTypeDefaultDescription
namestring—Queue name. Must match the queue option in defineSqsHandler.
delaySecondsnumber0Delivery delay in seconds.
maxMessageSizenumber262144Max message size in bytes.
retentionSecondsnumber345600Message retention in seconds (4 days).
visibilityTimeoutSecondsnumber30Visibility timeout in seconds.
enableDlqAlarmbooleantrueEnable CloudWatch alarm for DLQ message depth.

DynamoDB ​

typescript
dynamodb: [
  {
    name: "idempotency",
    hashKey: "id",
    attributes: [{ name: "id", type: "S" }],
    ttlAttribute: "expiration",
  },
];
OptionTypeDefaultDescription
namestring—Table logical name.
tableNameOverridestring—Full table name as Terraform expression.
hashKeystring—Partition key attribute name.
rangeKeystring—Sort key attribute name.
attributesarray—Attribute definitions. Each has name and type (S, N, B).
billingModestringPAY_PER_REQUESTPAY_PER_REQUEST or PROVISIONED.
ttlAttributestring—Attribute name for TTL-based expiry.
pointInTimeRecoverybooleanfalseEnable PITR.
globalSecondaryIndexesarray—GSI definitions. Each has name, hashKey, rangeKey?, projectionType?.

WebSocket ​

typescript
websocket: {
  routeSelectionExpression: '$request.body.action',
  stageName: 'live',
}
OptionTypeDefaultDescription
routeSelectionExpressionstring$request.body.actionRoute selection expression.
stageNamestringliveAPI Gateway stage name.
throttlingBurstLimitnumber100Burst limit.
throttlingRateLimitnumber50Rate limit (requests/second).

Observability ​

typescript
observability: {
  adot: true,
  metricsNamespace: 'MyApp',
}
OptionTypeDefaultDescription
adotbooleanfalseAttach AWS Distro for OpenTelemetry (ADOT) layer to all Lambdas.
metricsNamespacestring—CloudWatch metrics namespace. Injected as METRICS_NAMESPACE env var.
commonEnvRecord<string, string>—Additional env vars injected into all Lambdas via locals.tf.

CORS ​

typescript
cors: {
  origins: ['https://app.example.com'],
  methods: ['GET', 'POST'],
  maxAge: 86400,
}
OptionTypeDefaultDescription
originsstring[]—Allowed origins. Empty = no CORS headers (secure default).
methodsstring[]['GET','POST','PUT','DELETE','PATCH','OPTIONS']Allowed HTTP methods.
headersstring[]['Content-Type','Authorization']Allowed request headers.
maxAgenumber86400Preflight cache max-age in seconds.

Secrets (SOPS) ​

typescript
secrets: {
  provider: 'sops',
  filePattern: 'secrets.{env}.enc.yaml',
}
OptionTypeDefaultDescription
provider'sops'—Secrets provider. Only sops is supported.
filePatternstringsecrets.{env}.enc.yamlEncrypted file pattern. {env} is replaced with staging or prod.

Per-Lambda secrets are mapped in defineLambda({ secrets: { ENV_VAR: 'sops.key.path' } }).


SNS ​

typescript
sns: {
  topics: [{ name: 'notifications' }],
  platformApplications: [
    {
      name: 'my-app',
      platform: 'APNS_SANDBOX',
      credentialSecret: 'apns.privateKey',
      principalSecret: 'apns.certificate',
    }
  ],
}
OptionTypeDescription
topics[].namestringTopic name. Wired as env var.
platformApplications[].namestringApplication name.
platformApplications[].platform'APNS' | 'APNS_SANDBOX' | 'GCM'Push platform.
platformApplications[].credentialSecretstringSOPS key path for the platform credential.
platformApplications[].principalSecretstringSOPS key path for the platform principal.
platformApplications[].resourceNamestringOverride for the Terraform resource identifier.

CloudFront (API Distribution) ​

typescript
cloudfront: {
  apiDistribution: {
    geoRestriction: { type: 'whitelist', locations: ['US', 'CA'] },
    forwardedHeaders: ['Authorization', 'X-API-Key'],
    cacheTtl: { default: 0, min: 0, max: 0 },
  }
}
OptionTypeDescription
apiDistribution.geoRestrictionobjecttype: whitelist or blacklist. locations: ISO 3166-1 alpha-2 codes.
apiDistribution.forwardedHeadersstring[]Headers forwarded to the origin.
apiDistribution.cacheTtlobjectCache TTL settings: default, min, max in seconds.

Custom Lambda Layers ​

typescript
layers: [
  {
    name: "ffmpeg",
    path: "layers/ffmpeg",
    compatibleArchitectures: ["x86_64"],
    description: "ffmpeg binary",
  },
];
OptionTypeDefaultDescription
namestring—Layer name. Referenced in defineLambda({ layers: ['local.ffmpeg_layer_arn'] }).
pathstring—Path to layer source directory, relative to project root.
compatibleArchitecturesstring[]['arm64']arm64 and/or x86_64.
compatibleRuntimesstring[]—Compatible runtimes (e.g. ['nodejs24.x']). Omit for binary-only layers.
descriptionstring—Human-readable description.

Custom Terraform Variables ​

typescript
customVariables: [
  {
    name: "api_quota_limit",
    type: "number",
    description: "Daily API quota",
    default: "10000",
  },
];
OptionTypeDescription
namestringVariable name.
typestringTerraform type expression: string, number, bool, list(string), etc.
descriptionstringVariable description.
defaultstringDefault value as Terraform expression string. Omit for required variables.
sensitivebooleanMark as sensitive (redacted in plan output, and redacted in deploy's binding warnings).
validationobjectcondition: Terraform expression. errorMessage: shown on violation.
valueFromstringProject-relative module whose default export returns the value. See below.

valueFrom — let the project compute a variable's value ​

valueFrom names a module inside the project. Its default export is a function returning the value as a string. mantle deploy invokes it and passes the result as -var, exactly as it passes the container image URIs and the deployment provenance facts. Nothing is exported into the environment as TF_VAR_.

typescript
customVariables: [
  {
    name: "llm_spec_contract",
    type: "string",
    description: "Spec contract the composer fail-closes without",
    valueFrom: "scripts/llm-provenance-contract.mjs",
    validation: { regex: "^package:[0-9.]+/rule:[0-9]+$" },
  },
];
javascript
// scripts/llm-provenance-contract.mjs
export default function computeSpecContract() {
  return `package:${version}/rule:${ruleCount}`;
}

Behavior:

  • Binding is by variable name. The variable may be declared by this customVariables entry or by a Lambda's defineLambda({env}); either way deploy binds it. defineLambda stays the single place a Lambda says what it reads. When both declare the same name, the valueFrom entry supplies the generated variable block, so its description and validation reach variables.tf instead of the machine-derived description.
  • Resolution runs before any side effect — before the build, the ECR push, and the apply.
  • The provider may be sync or async; the result is awaited. There is no timeout: a provider that never settles hangs the deploy before anything is written.
  • The returned string is trimmed, matching how an explicit TF_VAR_ binding is read.
  • validation is enforced twice: by the CLI against the resolved value before the deploy proceeds, and by tofu at plan time through the generated validation block. A raw HCL condition is enforced by tofu only — the CLI cannot evaluate HCL.
  • An explicit TF_VAR_<name> wins, with the same precedence the provenance facts use: a blank value counts as unset, and a divergence between the explicit value and the provider's is reported. A CI job already binding the value keeps working unchanged.

deploy refuses, with a named message and before any side effect, when: the module is missing, fails to bundle or import, exports no callable default, throws, returns a non-string, returns a blank string, or returns a value failing the declared validation. It also refuses the declaration itself when name is a framework-owned variable (environment, api_bearer_token, log_level, the provenance facts, image_uri_*, and the rest), when two entries claim one name, or when valueFrom is absolute or points outside the project — each of those would bind a value the project did not intend, or bind a different value on CI than on a laptop.


Authorizer ​

typescript
authorizer: {
  cacheTtl: 0;
}
OptionTypeDefaultDescription
cacheTtlnumber300Token cache TTL in seconds. 0 disables caching and identity source validation.

CI ​

Consumed by mantle ci and by GitHub Actions workflow generation.

typescript
ci: {
  deploy: true,
  customSteps: [
    { name: "contract-check", command: "pnpm run check:contract", phase: "Validate" },
  ],
}
OptionTypeDefaultDescription
deployboolean—Run deployment after CI passes.
customStepsarray—Instance-specific steps run alongside the built-in pipeline.

Each entry in customSteps is { name, command, phase }. A custom step is treated as optional for fail-fast ordering, but it still fails the pipeline when it runs and exits non-zero.


OpenAPI ​

Consumed by mantle generate openapi.

typescript
openapi: {
  additionalSchemas: [
    { source: "#types/notification-schemas", prefix: "Notifications." },
  ],
}
OptionTypeDescription
additionalSchemasarrayExtra Zod schema files to emit as standalone components in the generated spec.

Each entry is { source, prefix }: source is a TypeScript path alias to the schema file, prefix is prepended to every generated component name from that file.


AWS SDK Application ID ​

typescript
awsSdkAppId: "my-api";
OptionTypeDescription
awsSdkAppIdstringEmitted as AWS_SDK_UA_APP_ID on every Lambda.

Sets the AWS SDK user-agent application identifier, which makes per-application CloudTrail and Cost Explorer filtering possible. Maximum 50 characters; allowed characters are A-Z a-z 0-9 ! $ % & ' * + - . ^ _ | ~. When undefined, no AWS_SDK_UA_APP_ID variable is emitted.


Extended CLI Config ​

For CI, hooks, and conventions settings beyond the ci block above, use defineToolingConfig from @j0nathan-ll0yd/cli/config instead of defineConfig. See the CLI reference for details.