WebApp
A WebApp is a long-running HTTP service. Use it when you want persistent state across requests — DB connection pools, in-memory caches, sticky sessions, framework lifecycle hooks. Contrast with Function (per-event, cold-start tolerant) and API (request-driven serverless HTTP).
Quick example
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 apiKey = new Secret(app, 'api-key', {});
export const web = new WebApp(app, 'web', {
handler: './src/server.ts',
port: 8080,
cpu: '0.25',
memory: 512,
minInstances: 1,
maxInstances: 5,
bindings: { db, apiKey },
});
Your handler is a normal HTTP server:
import { createServer } from 'node:http';
import { db, apiKey } from '../infra.js';
const port = Number(process.env.PORT ?? 8080);
createServer(async (req, res) => {
const key = await apiKey.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({ keyPrefix: key.slice(0, 6), rows }));
}).listen(port);
Config
interface WebAppConfig {
handler: string;
runtime?: 'nodejs22' | 'nodejs20' | 'python3.12';
port?: number; // default 8080
cpu?: '0.25' | '0.5' | '1' | '2'; // default '0.5'
memory?: number; // MB, default 1024
minInstances?: number; // default 1
maxInstances?: number; // default = minInstances
env?: Record<string, string>;
bindings?: Record<string, Database | Bucket | Secret | Queue>;
}
Valid cpu / memory combinations on AWS Fargate — 0.25 vCPU allows 512–2048 MB; 0.5 vCPU requires ≥1024 MB. If you pick an invalid combo the deploy fails with a clear message.
Target mapping
| Target | Maps to | Notes |
|---|---|---|
aws | ECS Express (Fargate) | Replaced App Runner (closed to new customers 2026-04-30). Autoscaling, ALB-fronted HTTPS endpoint. |
sprintsail-runtime | Deployment + Service + Ingress (Contour) | HTTPS via cert-manager when a sail-issuer ClusterIssuer exists. Plain HTTP otherwise. |
Runtime behavior
The user file is expected to start an HTTP server on config.port (default 8080). The SDK does not wrap it. PORT is injected as an env var.
On both targets your container gets the runtime adapter installed before your code runs, so primitive runtime methods work transparently.
Ingress on the runtime
The Ingress hostname defaults to <project>-<name>.sail.localhost. For real clusters, set SAIL_INGRESS_DOMAIN at deploy time:
SAIL_INGRESS_DOMAIN=example.com sail deploy --target sprintsail-runtime:prod
# -> Ingress host: orders-web.example.com
Configure your DNS (or sslip.io for a quick public URL pointed at the node's IP).
Health checks
A TCP readiness probe on config.port is added automatically on the runtime. On AWS, ECS Express uses the load balancer's health-check path (/ by default).