Skip to main content
RapidDev - Software Development Agency
outsystems-tutorial

Client Actions vs Server Actions: When to Use Which in OutSystems

Client Actions run in the browser and can access screen widgets and Client Variables but not the database. Server Actions run on the server and can access the database, Site Properties, and external APIs but not the screen. Always use Server Actions for data operations and Client Actions for UI logic. Call Server Actions from Client Actions when you need both.

What you'll learn

  • The fundamental difference between Client Action and Server Action execution contexts
  • Which operations are only possible in Server Actions (database, APIs, Site Properties)
  • Which operations are only possible in Client Actions (widgets, navigation, JavaScript)
  • How to call a Server Action from a Client Action and pass data between them
  • The Data Action type in Reactive apps and when to use it over a Server Action
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner8 min read20-30 minOutSystems 11 and ODCMarch 2026RapidDev Engineering Team
TL;DR

Client Actions run in the browser and can access screen widgets and Client Variables but not the database. Server Actions run on the server and can access the database, Site Properties, and external APIs but not the screen. Always use Server Actions for data operations and Client Actions for UI logic. Call Server Actions from Client Actions when you need both.

Client Actions vs Server Actions in OutSystems

The single most common certification question and beginner confusion point in OutSystems is: 'Where should I put this logic?' The answer depends entirely on where the code needs to run. Client Actions run in the browser (JavaScript), Server Actions run on the .NET server. They live in different worlds and have different capabilities. Getting this right prevents security holes, unnecessary server round-trips, and TrueChange errors.

Prerequisites

  • Service Studio installed with a Reactive Web App open
  • Basic familiarity with the Logic tab and how to create actions

Step-by-step guide

1

Understand the two execution contexts

Before writing any code, internalize this mental model: Client Actions = JavaScript running in the user's browser. - Can see: screen widgets and their properties, Local Variables on the current screen, Client Variables (localStorage), navigate between screens, call JavaScript nodes, call other Client Actions. - Cannot see: database tables, Site Properties, Session Variables (O11 Traditional only), external APIs (CORS blocks direct browser calls). Server Actions = .NET code running on OutSystems Platform Server. - Can see: all entities (database), Site Properties, server-side sessions, external REST/SOAP APIs, email sending, file I/O. - Cannot see: screen widgets, Client Variables, browser state. This boundary is enforced by OutSystems — TrueChange will show a red error if you try to access a database entity from a Client Action.

Expected result: You can classify any operation into 'needs Client Action' or 'needs Server Action' before writing a single line of logic.

2

Create a Client Action for form validation and UI control

Client Actions are the right home for logic that reads or writes to screen widgets, validates user input before sending to the server, toggles visibility, or navigates. To create: right-click the screen name in the Widget Tree → 'Add Client Action'. Name it 'ValidateAndSubmitForm'. Or: right-click a Button widget → 'Add OnClick Client Action' — Service Studio creates it automatically. Example Client Action flow for a form submit: Start → If: Length(Trim(FullName)) < 2 → [True] Assign FullNameInput.Valid=False → End → [False continues] → If: Form.Valid → [True] calls SaveEmployee Server Action → [False] End Note: 'SaveEmployee' is a Server Action call node — you drag it from Logic tab → Server Actions into the Client Action flow.

typescript
1/* Client Action: ValidateAndSubmitForm */
2Start
3 --> If: Length(Trim(FullName)) < 2
4 [True] --> Assign: FullNameInput.Valid = False
5 FullNameInput.ValidationMessage = "Name too short"
6 --> End
7 --> If: Form.Valid
8 [True] --> SaveEmployee /* Server Action call */
9 Input: FullName, DepartmentId
10 --> Message: "Saved!" (Success)
11 --> End
12 [False]--> End

Expected result: A Client Action node appears under your screen in the Interface tab. Clicking the submit button runs the validation logic entirely in the browser before making any server call.

3

Create a Server Action for database operations

Server Actions belong to the module-level logic layer. They run on the server and can call entity actions (Create, Update, Delete, Get) and Aggregates. To create: Logic tab → Server Actions → right-click → 'Add Server Action'. Name it 'SaveEmployee'. Add Input Parameters: right-click the Server Action → Add Input Parameter: - FullName: Text - DepartmentId: Department Identifier Add Output Parameter: - EmployeeId: Employee Identifier Action flow: Start → CreateEmployee: Employee.FullName=FullName, Employee.DepartmentId=DepartmentId, Employee.CreatedAt=CurrDateTime() → Assign: EmployeeId = CreateEmployee.Id → End The CreateEmployee entity action is auto-generated when the Employee entity exists. Drag it from the Logic tab or Toolbox.

typescript
1/* Server Action: SaveEmployee
2 Input: FullName (Text), DepartmentId (Department Identifier)
3 Output: EmployeeId (Employee Identifier) */
4Start
5 --> CreateEmployee:
6 Employee.FullName = FullName
7 Employee.DepartmentId = DepartmentId
8 Employee.CreatedAt = CurrDateTime()
9 --> Assign: EmployeeId = CreateEmployee.Id
10 --> End

Expected result: SaveEmployee is available in the Logic tab under Server Actions. It can be dragged into Client Action flows as a call node.

4

Call a Server Action from a Client Action and handle the response

To connect Client and Server Actions, drag the Server Action into the Client Action flow. Service Studio creates a call node with input and output mapping. In ValidateAndSubmitForm (Client Action), after the Form.Valid True branch: - Drag SaveEmployee from Logic tab → Server Actions onto the flow - The call node shows input mappings: FullName → FullName, DepartmentId → DepartmentId - To use the output: after the call node, add an Assign: NewEmployeeId = SaveEmployee.EmployeeId - Then navigate: Destination node → EmployeeDetailScreen (pass NewEmployeeId as input) Every Server Action call crosses the network — minimize them by batching operations and avoiding calls inside loops.

typescript
1/* Client Action: ValidateAndSubmitForm - full flow */
2Start
3 --> (validation logic from Step 2)
4 --> If: Form.Valid
5 [True] --> SaveEmployee: FullName=FullName, DepartmentId=DepartmentId
6 --> Assign: NewEmployeeId = SaveEmployee.EmployeeId
7 --> Destination: EmployeeDetailScreen (EmployeeId=NewEmployeeId)
8 [False]--> End

Expected result: Submitting the form validates client-side, calls SaveEmployee once, gets back the new ID, and navigates to the detail screen.

5

Understand Data Actions and when to prefer them

Reactive Web and Mobile apps have a third action type: Data Actions. A Data Action is a server-side action that runs asynchronously when the screen loads, separate from the main render cycle. Create: right-click screen → 'Fetch data from Other Sources' → creates a Data Action. Data Actions are best for: - Fetching data that does not come from a single Aggregate (e.g., calling an API, running multiple aggregates and combining results) - Loading data that depends on complex server-side logic Data Actions are NOT for: - Simple database queries — use a Screen Aggregate instead (lighter weight) - Anything triggered by user interaction — use a Client Action that calls a Server Action Key behavior: Data Actions run in parallel with other screen data fetches and do not block the screen render. They provide a .Data output you bind to widgets.

Expected result: You can identify whether a given data-loading scenario calls for a Screen Aggregate, a Data Action, or a Client Action calling a Server Action on demand.

Complete working example

ClientServerAction_decision_guide.txt
1/* DECISION GUIDE: Client vs Server Action
2
3 USE CLIENT ACTION when:
4 - Setting widget.Valid, widget.ValidationMessage
5 - Toggling Visible property of a widget
6 - Navigating to another screen (Destination node)
7 - Running JavaScript (JavaScript node)
8 - Calling a Server Action and handling its output
9 - Updating Local Variables that bind to screen widgets
10
11 USE SERVER ACTION when:
12 - Reading from database (Aggregate or SQL node)
13 - Writing to database (Create/Update/Delete entity actions)
14 - Reading Site Properties
15 - Calling REST/SOAP APIs
16 - Sending emails
17 - Processing files (Binary Data)
18 - Any operation requiring server-side security
19
20 USE DATA ACTION when:
21 - Loading data on screen open that requires complex server logic
22 - Combining results from multiple sources before binding to screen
23*/
24
25/* EXAMPLE: Correct pattern for form submit */
26
27/* Client Action: SubmitForm */
28Start
29 [Client-side validation]
30 --> SaveRecord (Server Action call -- crosses network once)
31 --> Destination: NextScreen
32 --> End
33
34/* Server Action: SaveRecord */
35Start
36 --> GetRelatedData (Aggregate -- DB read)
37 --> CreateRecord (Entity action -- DB write)
38 --> CallExternalAPI (REST method -- network call)
39 --> End
40
41/* ANTI-PATTERN: Do NOT call Server Actions in a loop */
42/* BAD: */
43For Each Product in ProductList
44 --> SaveProduct (Server Action) /* N+1: 1 call per row = slow */
45End
46
47/* GOOD: batch the operation into one Server Action call */
48SaveAllProducts (Server Action, passes entire ProductList as input)

Common mistakes

Why it's a problem: Trying to access a database entity or run an Aggregate inside a Client Action

How to avoid: Entities and Aggregates are server-side. Move the data access to a Server Action with appropriate output parameters, then call it from the Client Action.

Why it's a problem: Calling a Server Action inside a For Each loop in a Client Action

How to avoid: This causes N+1 server calls (one per loop iteration). Move the batch logic into a single Server Action that accepts a list input and processes all items in one server round-trip.

Why it's a problem: Using a Client Variable to pass data 'into' a Server Action

How to avoid: Server Actions cannot read Client Variables. Pass data explicitly as input parameters when calling the Server Action from a Client Action.

Why it's a problem: Placing navigation (Destination node) inside a Server Action

How to avoid: Navigation is a client-side operation. Move the Destination node to the Client Action after the Server Action call completes and returns control.

Best practices

  • Never put database access logic (Aggregates, entity actions) in a Client Action — TrueChange will block publishing with a red error.
  • Never put widget property assignments (InputName.Valid, widget.Visible) in a Server Action — Server Actions run on the server and cannot see screen state.
  • Minimize Server Action calls — each call is a network round-trip. Batch multiple operations into one Server Action rather than chaining multiple calls.
  • Pass only the data a Server Action needs as input parameters — never pass entire record lists when an Id will do.
  • Use Data Actions (asynchronous) over Server Actions called in OnInitialize (synchronous) for non-blocking screen data loading.
  • Mark Server Actions as Functions (returning a value) when they are pure computations with no side effects — this enables use in expressions.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Explain the difference between Client Actions and Server Actions in OutSystems 11 Reactive Web. What can each type access? Show me the correct pattern for a form submit that validates in a Client Action and saves to the database in a Server Action, using OutSystems action flow arrow notation.

OutSystems Prompt

Create a form submit pattern in my OutSystems screen: (1) ButtonSaveOnClick Client Action that validates FullName length using Length(Trim(FullName)) < 2 and checks Form.Valid, (2) SaveEmployee Server Action with input parameters FullName (Text) and DepartmentId (Department Identifier) that calls CreateEmployee entity action, (3) wire the Client Action to call the Server Action on valid submission and navigate to EmployeeDetailScreen passing the new EmployeeId output.

Frequently asked questions

Can I call a Client Action from a Server Action?

No. A Server Action runs on the server and has no way to invoke browser-side logic. The call direction is always Client Action → Server Action. If your Server Action needs to update the UI, return values as output parameters and let the Client Action handle the UI update after the Server Action completes.

What is a Service Action and how does it differ from a Server Action?

A Service Action is a Server Action that is explicitly exposed for use by other modules. It is created in Logic tab → Service Actions (not Server Actions). Regular Server Actions are module-private. Service Actions are the OutSystems equivalent of a public API between modules. In ODC, all inter-app calls use Service Actions.

Is there a performance cost to calling a Server Action from a Client Action?

Yes — every Server Action call is an HTTP round-trip from the browser to the server. Keep Server Action calls to a minimum. For simple UI operations like toggling visibility or clearing a form, use Client Actions only. For data operations, batch work into as few Server Action calls as possible.

Can I make a Server Action run asynchronously?

Not natively in a single call. The standard Server Action call is synchronous (the Client Action waits for the result). For background processing, use Timers (Processes tab → Timers) which run as scheduled jobs on the server, or ODC Workflows for more complex async patterns.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.