Configuration
Use carlin.ts when deployment values need TypeScript, validation, or secrets from environment variables. The recommended API is defineConfig from carlin/config.
Typed Configuration
import { defineConfig, requiredEnv } from 'carlin/config';
const values = {
Staging: {
domainName: 'api-staging.example.com',
databaseHost: 'staging.cluster.example.com',
},
Production: {
domainName: 'api.example.com',
databaseHost: 'production.cluster.example.com',
},
};
export default defineConfig(({ environment }) => {
const current = values[environment || 'Staging'];
return {
lambdaFormat: 'cjs',
parameters: {
DomainName: current.domainName,
DatabaseHost: current.databaseHost,
DatabaseUsername: requiredEnv({ name: 'DATABASE_USERNAME' }),
DatabasePassword: requiredEnv({ name: 'DATABASE_PASSWORD' }),
},
};
});
defineConfig keeps autocomplete for Carlin options and validates the resolved config before deploy. It catches invalid parameters, missing parameter values, and invalid environments shape early. requiredEnv fails fast when a required .env or CI variable is missing.
Configuration Flow
Carlin loads dotenv automatically. When an environment is resolved (--environment, --env, -e, CARLIN_ENVIRONMENT, or ENVIRONMENT), Carlin first loads .env.<Environment> and falls back to .env only when that file does not exist. Without a resolved environment, Carlin loads .env. CI variables remain available through process.env, and the resolved environment is passed to defineConfig function configs.
The object returned by carlin.ts becomes the CLI config. During carlin deploy, parameters are converted into CloudFormation stack parameters. Prefer the object form for ordinary values:
parameters: {
DomainName: 'api.example.com',
DatabasePort: 5432,
}
Use the array form only when you need CloudFormation-specific fields such as usePreviousValue:
parameters: [
{
key: 'DatabasePassword',
usePreviousValue: true,
},
];
Your template declares the same parameter names and uses Ref where resources need the values:
export default {
Parameters: {
DomainName: { Type: 'String' },
DatabasePassword: { Type: 'String', NoEcho: true },
},
Resources: {
Function: {
Type: 'AWS::Lambda::Function',
Properties: {
Environment: {
Variables: {
DOMAIN_NAME: { Ref: 'DomainName' },
DATABASE_PASSWORD: { Ref: 'DatabasePassword' },
},
},
},
},
},
};
Secrets should stay in .env, CI secret stores, or existing CloudFormation parameter values. When a secret is passed as a CloudFormation parameter, mark the template parameter with NoEcho: true.
Environment Blocks
You can still use environments when you prefer declarative inheritance:
import { defineConfig, requiredEnv } from 'carlin/config';
export default defineConfig({
parameters: {
DatabasePort: 5432,
},
environments: {
Staging: {
parameters: {
DomainName: 'api-staging.example.com',
DatabasePassword: requiredEnv({ name: 'STAGING_DATABASE_PASSWORD' }),
},
},
Production: {
parameters: {
DomainName: 'api.example.com',
DatabasePassword: requiredEnv({ name: 'PRODUCTION_DATABASE_PASSWORD' }),
},
},
},
});
For secrets, prefer the function form when each environment has different required variables. It only reads the variables needed for the selected environment.