Core Concepts
/
Compile & Relations
Compile & Relations
How rastack compile reads the type system to infer foreign keys and emit the manifest.
The compile step is where the type system becomes a schema. rastack compile builds a real ts.Program and TypeChecker, walks each resource(...) call, and reads each field's type.
Foreign keys are inferred, not declared
A field whose type is a reference to another resource is a foreign key. The compiler recovers the target from the Ref<App, Model> string-literal type arguments — you write the relation once, as a type, and never again.
1
export
const
Terminal
=
resource
(
"airports"
,
"terminal"
,
{
2
airport
:
s
.
ref
(()
=>
Airport
),
// Ref<"airports", "airport">
3
label
:
s
.
string
({
maxLength
:
20
}),
6
// The compiler emits, in the manifest:
7
// relations: [{ field: "airport", target: "airports.airport", kind: "fk" }]
The DSL — resource() and s.*.
Builds the ts.Program + TypeChecker.
Walks each resource call and reads field types.
Emits schema.rastack.json.
Emits openapi.json with the FK and sync extensions.
The compiler emits paths in exactly the shape the codegen expects, so the hook generator and runtime never change:
1
/api/{appName}/v1/{modelName}/ ← list endpoint
2
/api/{appName}/v1/{modelName}/{id}/ ← detail endpoint
› Good to know
The codegen derives appName from path.split('/')[2] and modelName from path.split('/')[4]. Because the compiler emits this exact shape, the existing hooks codegen is unchanged.
Build with AI
Every page is available as clean Markdown for LLMs and coding agents. Point one at the files below to build on top of React API Stack.
React API Stack · alpha · built to scale to millions