Modular Dependencies, Public/Private Elements, and Layered Architecture
Key Takeaways
- OutSystems elements default to Private; setting Public = Yes exposes them to consumer modules via the Add Dependencies window in Service Studio.
- The four-layer canvas (End-User, Process, Core, System) enforces one-way downward dependencies — higher layers reference lower layers, never the reverse.
- Service Actions are Public Server Actions with a strict input/output contract, recommended for exposing business logic from Core and Process layers.
- Expose Read Only on an entity reference blocks Create, Update, CreateOrUpdate, and Delete operations while still allowing Aggregates and SQL queries.
- Circular dependencies are forbidden; TrueChange blocks publishing a module that would create an upward dependency in the layered canvas.
Quick Answer: OutSystems modules expose Public elements (Actions, Entities, Blocks, Screens, Roles) that other modules can reference; Private elements are internal. The platform's four-layer canvas (End-User, Process, Core, System) enforces one-way downward dependencies, preventing circular references. Service Actions expose business logic with a clean input/output contract, and entity references can be marked Expose Read Only to prevent lower layers from mutating core data.
Public vs Private Elements
Every element you create in an OutSystems module — Server Action, Entity, Screen, Block, Role, Structure, Static Entity — has a Public property. When Public is Yes, the element appears in the producer's public API and can be referenced by consumer modules. When Public is No (the default for most elements), the element is visible only inside its owning module. This is the primary encapsulation boundary in OutSystems: modules publish a curated surface and hide their internal implementation.
The producer-consumer model works as follows. A producer module owns the element and sets Public = Yes. A consumer module adds a Reference to that element via the Add Dependencies window in Service Studio. Once referenced, the consumer can call the Action, query the Entity, or drop the Block onto a Screen. The producer retains ownership; the consumer gets a read-only reference it cannot modify. If the producer renames or deletes a public element, TrueChange flags all consumers that depend on it so they can be fixed before publishing.
| Element Type | Default Public | Typical Use When Public |
|---|---|---|
| Server Action | No | Expose as Service Action for cross-module business logic |
| Entity | No | Share core data across layers |
| Block | No | Shared UI components across modules |
| Role | No | Security roles consumed by end-user modules |
| Structure | No | DTOs for REST or Service Action contracts |
Layered Architecture (Four-Layer Canvas)
OutSystems prescribes a four-layer canvas to organize modules by responsibility. Dependencies may only point downward — a module in a higher layer may reference modules in the same layer or any lower layer, never upward. This rule is structural, not advisory: TrueChange enforces it at design time.
| Layer | Purpose | Can Reference |
|---|---|---|
| End-User | UI for a specific user role or audience | Process, Core, System |
| Process | Business process orchestration and BPT workflows | Core, System |
| Core | Core entities and shared domain logic | System |
| System | External integrations and platform wrappers | Nothing internal |
The critical rule: no circular dependencies. Because references flow downward only, a Core module cannot call an End-User Screen, and a System module cannot reference Core entities. This keeps the dependency graph a directed acyclic graph and makes applications maintainable. Service Studio's dependency graph view visualizes every reference your module makes and every module that references yours, so you can trace the full impact of a change before you publish.
An End-User layer module needs to call business logic owned by a Core layer module. What is the recommended approach?
Service Actions and Expose Read Only
Service Actions are the recommended mechanism for exposing business logic from Core and Process layers to higher layers. A Service Action is a Server Action with Public = Yes that defines a strict input/output contract. Consumers see only the parameters and outputs — never the internal flow, local variables, or entities the producer uses. This black-box encapsulation lets Core modules change their internal implementation without breaking consumers, as long as the contract stays stable.
When you need to expose data rather than logic, you reference an Entity from a producer module. The reference can be marked Expose Read Only in the consumer. A read-only entity reference allows the consumer to run Aggregates and SQL queries against the entity but blocks Create, Update, CreateOrUpdate, and Delete entity actions. This prevents a lower-layer module from accidentally writing directly to a Core entity, forcing all writes through the producer's Service Actions where validation and business rules live.
| Reference Mode | Allowed Operations | Typical Consumer |
|---|---|---|
| Read/Write (default) | Aggregates, SQL, Create, Update, Delete | Same-layer or controlled Process module |
| Read Only | Aggregates and SQL queries only | End-User or lower layers referencing Core |
Dependency Graph Rules
The dependency graph in Service Studio shows every module your module references and every module that references yours. Key rules for the exam:
- Hard dependencies at publish time: If Module A references Module B, B must already be published to the target environment. Service Studio resolves the publish order automatically during 1-Click Publish.
- No circular dependencies: If A references B, B cannot reference A. The four-layer canvas prevents this structurally.
- Versioning matters: A consumer references a specific version of the producer. When the producer publishes a new version, the consumer must Update Dependencies to pick up changes; old references keep working against the previously published version until updated.
- Delete with caution: Deleting a public element that has consumers forces TrueChange errors in those consumers. OutSystems warns you but allows the delete; fixing consumers is a manual follow-up.
Exam Traps
A common exam scenario asks what happens when an End-User module tries to directly call a Core module's private Server Action. The answer: it cannot — the action is Private and will not appear in the Add Dependencies window. The fix is to expose it as a Service Action or route the call through a Process-layer wrapper. Another trap: a Core module referencing an End-User Screen violates the four-layer canvas and TrueChange blocks the publish. Remember that making an entity reference Read Only does not prevent reading; it only blocks write operations. Aggregates and SQL SELECT queries work normally against read-only references.
A consumer module references a Core entity marked Expose Read Only. Which operations are blocked?
Module A references Module B. What must be true before Module A can be published?