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
| Primitive | What it is | AWS | Sprintsail Runtime |
|---|---|---|---|
Function | A serverless function invoked per event. Scale to zero. | Lambda | Knative Service |
Worker | A long-running consumer that processes messages from a queue. | Lambda + SQS ESM | Deployment + in-process consume loop |
CronJob | A function that runs on a schedule. | Lambda + EventBridge | Kubernetes CronJob |
WebApp | An always-on HTTP server. DB pools persist; no cold starts. | ECS Express (Fargate) | Deployment + Service + Ingress |
API | Request-driven HTTP, single handler dispatches on path. | API Gateway v2 + Lambda | In-cluster shim + Ingress |
Storage
| Primitive | What it is | AWS | Sprintsail Runtime |
|---|---|---|---|
Database | A managed Postgres database. | RDS | CloudNativePG |
Bucket | An object store. S3-compatible API. | S3 | MinIO |
Messaging & Secrets
| Primitive | What it is | AWS | Sprintsail Runtime |
|---|---|---|---|
Queue | A durable message queue. | SQS | RabbitMQ cluster |
Secret | An encrypted credential. | Secrets Manager | SealedSecret → 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>).configis 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.