Get started with Sprintsail
Sprintsail is an opinionated TypeScript IaC SDK. You describe your application as a set of high-level primitives — Function, WebApp, Database, Bucket, Secret, ... — and the SDK provisions them on whichever target you point it at.
Today there are two targets:
aws— your AWS account. Primitives map to Lambda, ECS Express, RDS, S3, Secrets Manager, SQS, EventBridge.sprintsail-runtime— a managed Kubernetes runtime running exclusively open-source operators (Knative, CloudNativePG, MinIO, RabbitMQ, sealed-secrets, Contour, cert-manager). Same application code, no proprietary lock-in.
The headline workflow sail migrate --from aws --to sprintsail-runtime moves a deployed app between the two — infrastructure, data, secrets — with the same handler code.
Install
Sprintsail ships as an npm package + a CLI binary.
npm install --save-dev @sprintsail/sdk @sprintsail/cli
The CLI is exposed as sail. Add a script or run it via npx:
npx sail --help
Node 20+ is required.
Create a project
A Sprintsail project is two files plus your application code.
sail.config.ts — project name and default target.
import { defineConfig } from '@sprintsail/cli/config';
export default defineConfig({
project: 'orders',
defaultTarget: 'aws:us-east-1',
});
infra.ts — primitives, declared as TypeScript objects.
import { Project, Database, Secret, WebApp } from '@sprintsail/sdk';
export const app = new Project('orders');
export const db = new Database(app, 'orders', {
engine: 'postgres',
version: '16',
});
export const stripeKey = new Secret(app, 'stripe-key', {});
export const web = new WebApp(app, 'web', {
handler: './src/server.ts',
port: 8080,
cpu: '0.25',
memory: 512,
bindings: { db, stripeKey },
});
src/server.ts — your application. The bindings you declared in infra.ts are usable directly; the runtime adapter wires them up.
import { createServer } from 'node:http';
import { db, stripeKey } from '../infra.js';
const port = Number(process.env.PORT ?? 8080);
createServer(async (req, res) => {
const key = await stripeKey.value();
const rows = await db.query('SELECT id, amount FROM orders ORDER BY id LIMIT 50');
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ apiKey: key.slice(0, 6) + '…', rows }));
}).listen(port);
Deploy
npx sail deploy --yes
This is fully idempotent. Re-running adopts existing resources and only rolls what changed.
The first deploy provisions the Database (RDS takes ~5–10 min), the Secret, builds the WebApp container, pushes it to ECR, and stands up an ECS Express service. You get back a public URL.
To deploy to the Sprintsail Runtime instead:
npx sail deploy --target sprintsail-runtime:my-cluster --yes
(See Sprintsail Runtime for what a cluster needs.)
Migrate between targets
This is the workflow the SDK is built around — the no-lock-in story.
npx sail migrate \
--from aws:us-east-1 \
--to sprintsail-runtime:my-cluster \
--yes
sail migrate walks the source state, provisions equivalents on the destination, then copies stateful data — RDS rows to CloudNativePG via an in-cluster pg_dump | psql Job, Secrets Manager values into sealed-secrets, S3 objects into MinIO — and generates a cutover script for your downstream consumers.
See The sail migrate model and the AWS → Runtime tutorial.
What to read next
- Primitives — the 9 things you can declare and what each maps to.
- CLI Reference — every
sailsubcommand. - Capability Matrix — what's
stable/alpha/plannedon each target. - Quickstart tutorial — guided walkthrough of the above, end-to-end.