Splitting app logic

A traditional FileMaker layout defines the user interface (UI) to your application. It may contain buttons, hide calculations, script triggers, and more that affect the logic of your app. Traditional FileMaker scripts may also interact with those UI elements to change the visibility of items or navigate to different pages. All of these UI interactions can be replicated in JavaScript code running in the Web Viewer.

Every interaction with data in your app will still run through a FileMaker script, but it's up to you how much of the core business logic runs in JavaScript vs a FileMaker script.

For simple data updates, JavaScript can use the Data API to read/write/edit/delete records directly, but for more complex operations (like when you want to edit multiple records in a transaction) you'll want to write a custom FileMaker script — see "What belongs in FileMaker" below for how to decide, and Call FileMaker Scripts from an App for the fmFetch/callFMScript calling contract.

What belongs in the HTML/JavaScript

UI and interaction logic — the equivalent of what a layout, a button, or a script trigger would have done — belongs in JavaScript outright.

  • Showing, hiding, or rearranging elements.

  • Navigating between views.

    • You can also trigger navigation from a FileMaker script. See Navigation

  • Responding to user input (the Web Viewer equivalent of a script trigger).

  • Form state, in-progress edits, loading and error states.

What belongs in FileMaker

Reach for a FileMaker script once a data operation needs more than the write itself. That covers:

  • Anything spanning multiple records or multiple steps that must succeed or fail together (a transaction).

  • Anything that should trigger additional side effects after the record changes — updating related records, running a business rule, sending a notification.

  • Business rules that already live in FileMaker, or that need to be enforced no matter what called them.

  • Validation before creating, updating, or deleting records.

  • Anything involving a secret, an external API call, file system access, printing, PDF generation, or container handling.

How to decide

For a given data operation, ask: does anything else need to happen besides this one record changing?

  • No — it's a plain create, read, update, or delete, and nothing else depends on it → the Data API from JavaScript is a reasonable default, though a script is always a valid choice if you'd rather keep that logic in FileMaker.

  • Yes — multiple records, a transaction, a side effect, a business rule, or anything needing FileMaker's own security or data model → a script.

UI and interaction logic doesn't go through this test at all — it's JavaScript by default, independent of what the data operation underneath it needs.

Data API CRUD (the generated clients from Generate and Use a Typed Data Client) has no concept of a FileMaker transaction. If a workflow needs to create an invoice and its line items atomically, or edit several related records as one unit, that belongs in a script — not a sequence of create()/update() calls from the browser.

Copy
await InvoiceLayout.create({ fieldData: invoice });
await LineItemLayout.create({ fieldData: lineItem });
Copy
import { fmFetch } from "@adt/fmdapi";

await fmFetch("Create Invoice With Line Items", {
  invoice,
  lineItems,
});

Scripts run inside FileMaker's own security and data model. That lets the app ask FileMaker to do privileged work — enforce a business rule, run a multi-record transaction, call an API with a secret key — without moving any of that logic, credentials, or platform-specific behavior into browser JavaScript. See Call FileMaker Scripts from an App for the fmFetch/callFMScript calling contract.