effect-patterns

Effect TypeScript Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "effect-patterns" with this command: npx skills add 5dlabs/cto/5dlabs-cto-effect-patterns

Effect TypeScript Patterns

Type-safe error handling and composable services using Effect as the core type system for Node.js/Bun backends.

Core Stack

Component Library Purpose

Runtime Bun 1.1+ Fastest Node.js-compatible runtime

Framework Elysia 1.x End-to-end type safety

Type System Effect 3.x TypeScript's missing standard library

Validation Effect Schema Type-safe validation (replaces Zod)

HTTP Client @effect/platform HTTP operations

Database Drizzle ORM TypeScript ORM

Testing Vitest, bun:test Test framework

Context7 Library IDs

Query these libraries for current best practices:

  • Effect: /effect-ts/effect

  • Elysia: elysiajs

  • Drizzle: /drizzle-team/drizzle-orm

Effect Documentation

Before implementing Effect code, consult:

Typed Errors

Define errors as classes extending Schema.TaggedError :

import { Schema } from "effect"

class UserNotFoundError extends Schema.TaggedError<UserNotFoundError>("UserNotFoundError")({ userId: Schema.String, }) {}

class ValidationError extends Schema.TaggedError<ValidationError>("ValidationError")({ message: Schema.String, field: Schema.String, }) {}

class DatabaseError extends Schema.TaggedError<DatabaseError>("DatabaseError")({ message: Schema.String, }) {}

Services with Context.Tag

Define services with typed interfaces:

import { Effect, Context, Layer } from "effect"

class UserRepository extends Context.Tag("UserRepository")< UserRepository, { findById: (id: string) => Effect.Effect<User, UserNotFoundError> create: (data: CreateUser) => Effect.Effect<User, ValidationError> }

() {}

class DatabaseService extends Context.Tag("DatabaseService")< DatabaseService, { query: <T>(sql: string) => Effect.Effect<T[], DatabaseError> }

() {}

Layer Implementation

Implement services with Layer:

const UserRepositoryLive = Layer.succeed( UserRepository, UserRepository.of({ findById: (id) => Effect.tryPromise({ try: () => db.findUser(id), catch: () => new UserNotFoundError({ userId: id }) }), create: (data) => Effect.tryPromise({ try: () => db.createUser(data), catch: (e) => new ValidationError({ message: String(e), field: "unknown" }) }) }) )

const DatabaseServiceLive = Layer.succeed( DatabaseService, DatabaseService.of({ query: (sql) => Effect.tryPromise({ try: () => db.query(sql), catch: (e) => new DatabaseError({ message: String(e) }) }) }) )

Effect.gen for Composition

Use generator syntax for composable logic:

const getUser = (id: string) => Effect.gen(function* () { const repo = yield* UserRepository const user = yield* repo.findById(id) return user })

const createUserWithAudit = (data: CreateUser) => Effect.gen(function* () { const repo = yield* UserRepository const user = yield* repo.create(data) yield* Effect.log(Created user: ${user.id}) return user })

Schema Validation

Use Effect Schema for validation:

import { Schema } from "effect"

const CreateUserSchema = Schema.Struct({ name: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(100)), email: Schema.String.pipe(Schema.pattern(/^[^@]+@[^@]+.[^@]+$/)), age: Schema.optional(Schema.Number.pipe(Schema.int(), Schema.positive())), }) type CreateUser = Schema.Schema.Type<typeof CreateUserSchema>

// Validate unknown data const validateUser = Schema.decodeUnknown(CreateUserSchema)

Error Handling with catchTags

Pattern match on typed errors:

const result = await Effect.runPromise( program.pipe( Effect.catchTags({ UserNotFoundError: (e) => Effect.succeed({ error: User ${e.userId} not found }), ValidationError: (e) => Effect.succeed({ error: Invalid ${e.field}: ${e.message} }), DatabaseError: (e) => Effect.succeed({ error: Database error: ${e.message} }), }) ) )

Retry with Schedule

import { Effect, Schedule } from "effect"

const fetchWithRetry = Effect.retry( fetchExternalApi, Schedule.exponential("1 second").pipe(Schedule.compose(Schedule.recurs(3))) )

Elysia + Effect Integration

import { Elysia, t } from "elysia" import { Effect } from "effect"

const app = new Elysia() .post("/api/users", async ({ body }) => { const program = Effect.gen(function* () { const validated = yield* Schema.decodeUnknown(CreateUserSchema)(body) const repo = yield* UserRepository return yield* repo.create(validated) })

return Effect.runPromise(
  program.pipe(
    Effect.provide(UserRepositoryLive),
    Effect.catchAll((e) => Effect.succeed({ error: e.message }))
  )
)

}, { body: t.Object({ name: t.String(), email: t.String({ format: "email" }), }) })

Testing with Effect

import { Effect, Layer } from "effect"

const TestUserRepository = Layer.succeed( UserRepository, UserRepository.of({ findById: (id) => id === "123" ? Effect.succeed({ id: "123", name: "Test User" }) : Effect.fail(new UserNotFoundError({ userId: id })), create: (data) => Effect.succeed({ id: "new", ...data }) }) )

// In tests const result = await Effect.runPromise( getUser("123").pipe(Effect.provide(TestUserRepository)) )

Validation Commands

bun tsc --noEmit bun eslint src/ bun test bun build src/index.ts --outdir=dist

Guidelines

  • Always define typed errors with Schema.TaggedError

  • Use Context.Tag for all services

  • Implement services with Layer.succeed

  • Compose logic with Effect.gen

  • Use Schema for all validation

  • Pattern match errors with catchTags

  • Provide layers at the edge of the application

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

code-review

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

github-mcp

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

test-driven-development

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

project-development

No summary provided by upstream source.

Repository SourceNeeds Review