# Configure Consistency Source: https://fragment.dev/guides/configure-consistency [Documentation index](https://fragment.dev/llms.txt) To ensure correctness at scale, Fragment's consistency mode lets you build guardrails without sacrificing performance. [Visual: configureConsistency. View on the HTML page.](https://fragment.dev/guides/configure-consistency) You can configure consistency within your Schema to make granular tradeoffs between throughput and consistency. ## Ledger Configuration You can configure the consistency of the Ledger Entries list query in your Ledger. To do this, set `consistencyConfig` at the top level of your Schema: - Use `entries: eventual` for Ledgers that require high throughput but can tolerate a stale entry list - Use `entries: strong` for Ledgers that have lower throughput but require strong consistency, such as those powering reconcilation dashboards ```json title="Configuring consistency" { "consistencyConfig": { "entries": "strong" }, "chartOfAccounts": [...] } ``` By default, all Ledgers use `eventual` consistency. ## Ledger Account Configuration You can configure the consistency of balances, as well as the Ledger Lines list query, in your Ledger Account. To configure an account's balance consistency, set `consistencyConfig.totalBalanceUpdates` within a Ledger Account's definition. `totalBalanceUpdates` controls the consistency with which the `selfTotal`, `childTotal` and total `balance` components of the account are updated. When `totalBalanceUpdates` is set to `strong`, any entry posted to the account or any of its children will update the account's balance immediately. Options: - Use `totalBalanceUpdates: eventual` for Ledger Accounts that require high throughput but can tolerate stale balances, such as those used for reporting - Use `totalBalanceUpdates: strong` for Ledger Accounts that have lower throughput but require strong consistency, such as those used to authorize transactions Similarly, to configure the consistency of an account's lines, set `consistencyConfig.lines`: - Use `lines: eventual` for Ledger Accounts that require high throughput but can tolerate a stale line list - Use `lines: strong` for Ledger Accounts that have lower throughput but require strong consistency, such as those powering transaction histories displayed to end users ```json title="Configuring consistency" { "accounts": [ { "key": "user-balance", "template": true, "type": "asset", "consistencyConfig": { "totalBalanceUpdates": "strong", "lines": "eventual" } } ] } ``` By default, all Ledger Accounts use `eventual` for both properties. For low-throughput applications, setting all Ledger Accounts as `strong` may make implementation easier. To do this, set `defaultConsistencyConfig` on `chartOfAccounts`: ```json title="Configuring default consistency" { "chartOfAccounts": { "defaultConsistencyConfig": { "totalBalanceUpdates": "strong", "lines": "strong" }, "accounts": [...] } } ``` Strongly consistent Ledger Accounts generally won't have children, but in all cases child Ledger Accounts inherit the parent's `consistencyConfig` setting. ## Balance queries To query a strongly consistent `balance`, set `consistencyMode` to `strong` when querying the Ledger Account: ```graphql title="Setting consistency on balance reads" query GetBalances( $ledgerAccount: LedgerAccountMatchInput! ) { ledgerAccount(ledgerAccount: $ledgerAccount) { balance(consistencyMode: strong) balances(consistencyMode: strong) { nodes { amount currency { code } } } } } ``` By default, balance queries on all Ledger Accounts are eventually consistent. Restrictions: - Querying a strongly consistent balance on an eventually consistent Ledger Account throws a GraphQL error - You cannot combine `at` with `consistencyMode` to query strongly consistent historical balances ## Entry conditions Entry conditions are rules defined in your Schema to manage concurrency and enforce correctness within your Ledger. Conditions are evaluated when a Ledger Entry is posted. If a condition is not met, the Ledger Entry is not posted and the mutation returns a `BadRequestError` with code `conditional_request_failed`. Use `precondition` when your application reads a balance and needs to guarantee that it hasn't changed before posting the Ledger Entry. ```json title="Using precondition" { "type": "pay-employee", "lines": [...], "conditions": [ { "account": { "path": "bank-account" }, "precondition": { "totalBalance": { "eq": "{{current_balance}}" } } } ] } ``` Use `postcondition` to guarantee that a write never puts a Ledger Account's balance in an undesirable state. ```json title="Using postcondition" { "type": "pay-employee", "lines": [...], "conditions": [ { "account": { "path": "bank-account" }, "postcondition": { "totalBalance": { "gte": "0" } } } ] } ``` Restrictions: - Entry conditions using `totalBalance` apply to the account's total balance, which includes both the account's own lines and its children's lines. - Ledger Accounts referenced in Entry conditions must have `consistencyConfig.totalBalanceUpdates` set to `strong` - Linked Ledger Accounts do not support Entry conditions ## Repeated conditions When using [repeated](https://fragment.dev/markdown/guides/post-ledger-entries.md#repeated-lines) Lines, conditions can be repeated using the same `repeated` key. This lets you enforce a condition on a variable set of accounts: ```json title="Ledger Entry with repeated lines and conditions" { "type": "batch_transfer", "lines": [ { "key": "from", "account": { "path": "liabilities/users:{{from_user}}/available" }, "amount": "-{{amount}}", "repeated": { "key": "transfers" } }, { "key": "to", "account": { "path": "liabilities/users:{{to_user}}/available" }, "amount": "{{amount}}", "repeated": { "key": "transfers" } } ], "conditions": [ { "account": { "path": "liabilities/users:{{from_user}}/available" }, "postcondition": { "totalBalance": { "gte": "0" } }, "currency": { "code": "USD" }, "repeated": { "key": "transfers" } } ] } ``` Each element in the `transfers` array generates both the transfer lines and its own balance condition. ## Consistent Groups You can configure an account to have a strongly-consistent ownBalance for specific group keys. To do this, use the `consistencyConfig.groups` configuration in the Schema. ```json title="Ledger Entry Group balance consistency" { "accounts": [ { "key": "user-balance", "template": true, "type": "asset", "consistencyConfig": { "groups": [ { "key": "invoice_id", "ownBalanceUpdates": "strong" } ] } } ] } ``` See [Group Ledger Entries](https://fragment.dev/markdown/guides/group-ledger-entries.md) for more information about how to use Ledger Entry Groups. ## Query Consistent Groups To query a strongly consistent Ledger Entry Group balance, set `consistencyMode` to `strong` or `use_account` when querying the group's balances. ```graphql title="Setting consistency on group ownBalance reads" query ListLedgerEntryGroupBalances( $ledger: LedgerMatchInput! $groupKey: SafeString! $groupValue: SafeString! $consistencyMode: ReadBalanceConsistencyMode ) { ledgerEntryGroup(ledgerEntryGroup: { ledger: $ledger, key: $groupKey, value: $groupValue, }) { balances { nodes { account { path } ownBalance(consistencyMode: $consistencyMode) } } } } ``` By default, Ledger Entry Group balances are eventually consistent. Like other consistency options, enabling strong consistency will reduce the maximum throughput of an account. Restrictions: - Ledger Entry Group balances cannot be used for Entry conditions. - Querying a strongly consistent Ledger Entry Group balance without configuring strong group consistency for that Ledger Account throws a GraphQL error. ## Legacy ownBalance Consistency `ownBalanceUpdates` is the legacy way of setting account level consistency. It only controls the consistency of the account's own balance (excluding children). `childTotal` and `balance` default to `eventual` on Schemas using `ownBalanceUpdates`. A Ledger Account cannot have both `totalBalanceUpdates` and `ownBalanceUpdates` set. Schemas using `ownBalanceUpdates` can only use `ownBalance` conditions. These conditions only apply to the account's own balance and require `consistencyConfig.ownBalanceUpdates` set to `strong`. Any examples or documentation on this page that use `totalBalanceUpdates` or `totalBalance` conditions can be adapted for a legacy `ownBalanceUpdates` Schema by replacing: - `totalBalanceUpdates` with `ownBalanceUpdates` in your consistency config - `totalBalance` with `ownBalance` in your entry conditions