effx
Concepts

Schema refs

effx keeps Effect Schemas and symbols by reference. SchemaRef and SymbolRef name an export. Generated code imports the original value.

The IR never contains a Schema value. It contains a reference to an exported symbol. Generated code imports that symbol, so there is one definition of every schema (ADR 0004).

Source: packages/ir/src/Refs.ts, docs/decisions/0004-schemas-preserved-by-symbol-reference.md, docs/specs/0001-compiler-kernel.md.

Why not serialize schemas

SchemaAST is a runtime tree with declarations, suspensions, transformations and annotations. It has no faithful pure-JSON form. Running application modules at build time to introspect them would add side effects and ordering hazards (ADR 0004).

The two references

TypeFieldsUsed for
SchemaRefmodule: string, export: string, symbolId: StableIdan Effect Schema value: operation input, success and error schemas, model views
SymbolRefmodule: string, export: string, member?: stringa value symbol: a handler method, a service class, a security middleware

symbolId of a SchemaRef is a schema: StableId. member names a static member, for example a handler method on a class.

packages/ir/src/Refs.ts (shape)
SchemaRef = { module, export, symbolId }
SymbolRef = { module, export, member? }

module is an import specifier. The frontend guarantees it resolves from the generated directory, and generators emit it verbatim (spec 0001). The suffix rule for relative specifiers is in Emit modes and targets.

What generated code does with them

Generated code imports the original value and passes it to Effect:

ADR 0004 (illustrative)
import { GetUserInput } from "../users/schemas"
Rpc.make("User.Get", { payload: GetUserInput, ... })

Effect performs encoding and decoding at runtime. effx does not copy schemas into DTOs.

What it means for authors

RuleReason
Input, success and error schemas must be explicit symbol references in annotationsthe frontend resolves them to exported symbols
A referenced symbol must be exportedgenerated files import it. Spec 0010 lists unexported root symbols and hidden source symbols as errors that stop generation.
Do not rely on build-time execution of your modulesschema introspection by execution is an explicit later feature (ADR 0004)

Where refs appear

PlaceReference
Operation.input, Operation.success, Operation.errors.valuesSchemaRef
Model.schema, Model.views[].schemaSchemaRef
Schema noderef: SchemaRef
Operation.handler, Service.symbol, HttpGroup.rootSymbolSymbolRef
Operation.requirements.valuesStableIds of service: nodes, not refs

Source: packages/ir/src/Node.ts.

In the annotation layer

Annotations carry the same references before interpretation. AnnotationArg has a Schema case (ref: SchemaRef, optional fields) and a Symbol case (ref: SymbolRef, optional security, identifier) (packages/compiler/src/Collected.ts). Decorators and builder chains lower to identical annotation arguments, which is what makes syntax equivalence testable.

On this page