Skip to main content

Quickstart

This walks you through a real deploy: a Database + Secret + WebApp on AWS. It's the sail-poc example shipped in the repo.

You'll need:

  • Node 20+
  • An AWS account + working credentials (aws sts get-caller-identity succeeds)
  • Docker running locally (for building the WebApp container)

1. Scaffold

mkdir orders && cd orders
npm init -y
npm install --save-dev @sprintsail/sdk @sprintsail/cli
mkdir src

2. Configure

sail.config.js

export default {
project: 'orders',
defaultTarget: 'aws:us-east-1',
};

(.js works for both config and infra. TypeScript also supported.)

3. Define infrastructure

infra.js

import { Project, Database, Secret, WebApp } from '@sprintsail/sdk';

export const app = new Project('orders');

// publiclyAccessible so the in-cluster migrate Job can reach it later if you migrate.
export const db = new Database(app, 'orders', {
engine: 'postgres',
version: '16',
publiclyAccessible: true,
});

export const apiKey = new Secret(app, 'api-key', {
initialValue: 'sk-orders-demo-key',
});

export const web = new WebApp(app, 'web', {
handler: './src/server.ts',
port: 8080,
cpu: '0.25',
memory: 512,
bindings: { db, apiKey },
});

4. Write the application

src/server.ts

import { createServer } from 'node:http';
import { db, apiKey } from '../infra.js';

const port = Number(process.env.PORT ?? 8080);

let schemaReady = false;
async function ensureSchema() {
if (schemaReady) return;
await db.query(
'CREATE TABLE IF NOT EXISTS orders (id serial primary key, customer text, amount integer)',
);
schemaReady = true;
}

createServer((req, res) => {
void (async () => {
if (req.url === '/healthz') {
res.writeHead(200); res.end('ok\n'); return;
}
await ensureSchema();
const key = await apiKey.value();
const rows = await db.query('SELECT id, customer, amount FROM orders ORDER BY id LIMIT 50');
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ keyPrefix: key.slice(0, 6), count: rows.length, rows }, null, 2));
})();
}).listen(port);

5. Deploy

npx sail deploy --yes

You'll see the plan, then the provisioning steps roll out. RDS takes ~5–10 minutes the first time; ECS Express takes ~2 minutes. When it finishes you'll have a public URL.

Plan for project "orders" → aws:us-east-1:
+ database orders
+ secret api-key
+ webapp web
[aws/database] creating orders-orders (postgres 16, db.t4g.micro). Status will be "available" in ~5-10 min.
[aws/secret] created orders/api-key
[aws/webapp] preparing orders-web
[aws/webapp] docker push 107537841227.dkr.ecr.us-east-1.amazonaws.com/sprintsail/orders-web:...
[aws/webapp] created orders-web
[aws/webapp] status: ACTIVE

Deploy complete.

Hit the URL — the WebApp will create the schema on first request and return an empty rows.

6. Seed some data

Find the RDS master credentials in Secrets Manager (the AWS provider names them <project>/orders-credentials):

aws secretsmanager get-secret-value --secret-id orders/orders-credentials \
--query SecretString --output text

Then psql and insert a few rows. (For seeding from your laptop you'll need to open the RDS security group to your IP on 5432.)

INSERT INTO orders (customer, amount) VALUES
('Ada Lovelace', 4200),
('Alan Turing', 1942),
('Grace Hopper', 1906);

Reload the WebApp URL — you'll see the rows in the JSON response.

7. Tear down

npx sail destroy --yes

This deletes the ECS service, the Lambda role, the Secret (7-day recovery), and the RDS instance. Bucket primitives (if any) refuse to delete if non-empty — empty them first.

Next