Skip to main content

Primitives

A primitive is a high-level building block — a piece of your application's infrastructure that has a known shape and a known mapping on every target. You declare primitives in infra.ts; the SDK provisions them.

There are nine. Three kinds, by category.

Compute

PrimitiveWhat it isAWSSprintsail Runtime
FunctionA serverless function invoked per event. Scale to zero.LambdaKnative Service
WorkerA long-running consumer that processes messages from a queue.Lambda + SQS ESMDeployment + in-process consume loop
CronJobA function that runs on a schedule.Lambda + EventBridgeKubernetes CronJob
WebAppAn always-on HTTP server. DB pools persist; no cold starts.ECS Express (Fargate)Deployment + Service + Ingress
APIRequest-driven HTTP, single handler dispatches on path.API Gateway v2 + LambdaIn-cluster shim + Ingress

Storage

PrimitiveWhat it isAWSSprintsail Runtime
DatabaseA managed Postgres database.RDSCloudNativePG
BucketAn object store. S3-compatible API.S3MinIO

Messaging & Secrets

PrimitiveWhat it isAWSSprintsail Runtime
QueueA durable message queue.SQSRabbitMQ cluster
SecretAn encrypted credential.Secrets ManagerSealedSecret → Kubernetes Secret

Why primitives, not raw resources?

A primitive is a stable contract. Database means "managed Postgres I can db.query(sql) against." It doesn't mean RDS or CNPG specifically — those are implementation details of the target. Your application code never imports @aws-sdk/client-rds or pg; it imports db from infra.ts and calls db.query(...).

This is what makes sail migrate possible. The primitive contract is the boundary; everything below it is provider work.

Anatomy of a primitive

Every primitive has the same shape in code:

const x = new <Primitive>(<project>, '<name>', { ...config });
  • The primitive is registered with <project>.
  • <name> becomes part of every derived resource name (<project>-<name>).
  • config is the primitive-specific schema. The primitive reference pages document each one.

Some primitives also expose runtime methods you call from your handler — db.query(), bucket.put(), secret.value(), queue.publish(). Those go through the runtime adapter, which uses the right cloud SDK underneath based on which target you deployed to.

Bindings

To use a primitive in a handler, you have to bind it to the compute primitive that uses it:

const web = new WebApp(app, 'web', {
handler: './src/server.ts',
bindings: {
db: ordersDb,
receipts: receiptsBucket,
},
});

The binding name (db, receipts) is what the SDK projects into the handler's environment so the runtime adapter knows how to wire it. See Bindings.

Status per target

What's stable / alpha / planned on each target changes as the SDK lands work. The authoritative answer is:

npx sail target capabilities aws
npx sail target capabilities sprintsail-runtime

The Capability Matrix page mirrors the current state.