Effect-native SDKs for cloud providers
Tagged errors. Retry policies. Streaming pagination.
import * as S3 from "distilled-aws/s3"
const bucket = yield* S3.getBucket({
Bucket: "my-bucket"
}).pipe(
Effect.catchTag("NoSuchBucket", () =>
Effect.void
)
) Effect-native clients for major cloud providers, with tagged errors and tree-shakeable imports.
Complete AWS SDK with typed errors for S3, Lambda, DynamoDB, SQS, and 200+ services. Every API includes documented and undocumented error codes.
Cloudflare API client for Workers, R2, KV, D1, Queues, and more. Patched OpenAPI spec with complete error coverage.
PlanetScale MySQL serverless database client. Type-safe queries with proper connection and query error handling.
Neon serverless Postgres client. Branching, autoscaling, and type-safe database operations with complete error coverage.
Azure cloud services SDK. Blob Storage, Functions, Cosmos DB, and more with tagged errors.
Google Cloud Platform SDK. Cloud Storage, Cloud Functions, BigQuery, and Firestore with typed error handling.
The Problem
Every cloud provider ships incomplete specs. Errors are discovered at runtime, not compile time.
APIs return cryptic error codes that aren't in the documentation. You only discover them in production.
OpenAPI and Smithy specs are missing properties, wrong types, or outdated. The docs lie.
Errors you can't catch because they're not in the types. Your "exhaustive" switch statement isn't.
Import one function, bundle hundreds. Class-based SDKs can't tree-shake.
Effect-native cloud SDKs for modern TypeScript
Every API operation has properly typed, discriminated error unions. No more guessing what went wrong.
const bucket = yield* S3.getBucket({
Bucket: "my-bucket"
}).pipe(
Effect.catchTag("NoSuchBucket", () =>
Effect.succeed(null)
),
Effect.catchTag("AccessDenied", () =>
Effect.fail(new AuthError())
)
) Declarative, composable retry logic with type-safe schedules. Handle transient failures without callback hell.
const result = yield* S3.getObject({
Bucket: "my-bucket",
Key: "data.json"
}).pipe(
Effect.retry({
while: (e) => e._tag === "SlowDown",
schedule: Schedule.exponential("100 millis")
}),
Effect.timeout("5 seconds")
) Paginated APIs return Effect Streams. No manual token juggling—just iterate.
// Stream all pages
yield* S3.listObjectsV2
.pages({ Bucket: "my-bucket" })
.pipe(Stream.runForEach(Console.log))
// Or stream individual items
yield* DynamoDB.scan
.items({ TableName: "users" })
.pipe(Stream.runCollect) Upload and download with Effect Streams. Process data as it flows without buffering entire payloads.
// Upload a stream
yield* S3.putObject({
Bucket: "my-bucket",
Key: "large-file.bin",
Body: Stream.fromIterable(chunks),
})
// Download as a stream
const { Body } = yield* S3.getObject({ ... })
const text = yield* Body.pipe(
Stream.decodeText(),
Stream.mkString
) No monolithic client classes. Import only what you need—your bundle stays lean.
// Only bundles getBucket and createBucket
import * as S3 from "distilled-aws/s3"
// NOT this:
// import { S3Client } from "@aws-sdk/client-s3"
// new S3Client() bundles ALL 100+ operations The Mission
Type-safe, tagged error specs aren't just good for developers—they're essential for AI code generation.
distilled SDKs are built to power alchemy.run—next-generation Infrastructure-as-Code in native TypeScript. When AI generates infrastructure code, it needs to know every possible error and how to handle it.
Proper error tags mean sound, reliable tooling. No more hallucinated error handling. No more runtime surprises.