# Fragment vs. Postgres: who owns financial correctness?
Date: October 22, 2026
Author: Sophie Houser
Position: Software Engineer
Source: https://fragment.dev/blog/fragment-vs-postgres
[Documentation index](https://fragment.dev/llms.txt)
Fragment enforces configured financial posting rules outside the application code that calls it. Postgres can enforce financial rules too. The choice is who builds and maintains the posting engine, and which transaction boundaries your application needs.
| Responsibility | Fragment with Postgres | A ledger built in Postgres |
| --- | --- | --- |
| Financial posting engine | Reviewed entry types, balanced lines, ledger-write replay and configured balance conditions run in Fragment. | Your team implements and protects the posting interface, replay rules and concurrency controls. |
| Local transactions | Business state and ledger writes require coordination across services. | Business state, ledger records and outbox work can commit together in the same database. |
| Business correctness | Your application validates obligations, amounts, beneficiaries and approvals. | Your application validates the same business facts. |
| Payment execution | A payment provider moves money. Your application handles uncertainty and recovery. | The provider boundary still requires uncertainty handling and recovery. |
## What you delegate to Fragment
A deployed schema defines entry types and their accounting lines. The runtime applies those configured rules when callers post entries. Generated callers can change without reimplementing the posting engine. Your team still reviews the schema and controls its deployment.
| Mechanism | What it protects | Required conditions and limits |
| --- | --- | --- |
| Balanced entry types | Accounting lines follow the deployed entry definition. | Correct accounting structure does not establish a genuine invoice, correct amount or correct beneficiary. |
| Ledger-write idempotency | An identical posting retried with the same valid key replays that write. | New keys do not deduplicate business intent. Ledger keys do not deduplicate provider requests. |
| Entry conditions | Posting rejects writes that violate configured balance guards. | Eligible accounts need strong balance updates. Guards protect only their configured accounts and transitions. |
| Strong balance reads | Financial decisions can use current ledger balances. | Request strong reads on strongly updated accounts. A prior read does not reserve funds. |
Use [posting documentation](https://fragment.dev/guides/post-ledger-entries.md) and [consistency configuration](https://fragment.dev/guides/configure-consistency.md) when defining these rules. Linked accounts do not support entry conditions. Linked cash requires a reviewed internal reservation and clearing design.
- The application still validates events, amounts, currency, beneficiaries, destinations, approvals and expiry.
- Business-intent uniqueness needs its own control, even when each ledger write has an idempotency key.
- Schema-valid wrong parameters can still produce wrong business outcomes.
- Privileged schema changes and misuse of separate payment credentials remain outside these posting guarantees.
## What a Postgres ledger needs
A protected Postgres posting interface can enforce financial rules outside ordinary callers too. Its behavior depends on your implementation, permissions and migrations. Cross-row accounting invariants generally require more than a row-level `CHECK` constraint. See [PostgreSQL constraints](https://www.postgresql.org/docs/current/ddl-constraints.html).
| Mechanism you own | Design requirement |
| --- | --- |
| Accounting validation | Validate complete entries and enforce balanced lines per currency. |
| Write replay | Enforce stable write identities atomically, with defined behavior for conflicting payloads. |
| Concurrent reservations | Protect shared availability with reviewed locking or transactional concurrency controls. |
| Write permissions | Prevent application roles from bypassing the reviewed posting interface. |
| Maintenance | Review migrations and test simultaneous reservations, replay and bypass attempts. |
Postgres offers a genuine advantage when business state and ledger records share one database. Their changes and an outbox record can commit together. Separate databases in one cluster do not provide that ordinary local transaction. See [PostgreSQL database boundaries](https://www.postgresql.org/docs/current/manage-ag-overview.html).
- Choose a Postgres ledger when that local transaction matters and your team can maintain the financial engine.
- Choose Fragment when delegating configured posting enforcement justifies another service and its integration boundary.
- Neither choice removes business validation, payment-provider recovery or independent reconciliation.
## A rejected reservation under concurrency
Consider unlinked book cash of 10,000 USD minor units. Two payment commands each request 7,000. Each reservation moves payable into operation-specific pending liability and available cash into operation-specific reserved cash. Configure strong balance updates and nonnegative conditions on available cash and payable.
| Step | Available book cash | Result |
| --- | ---: | --- |
| Initial state | 10,000 | Valid obligations and independently supported funds already exist. |
| First guarded reservation | 3,000 | Acknowledged reservation permits the worker to request payment. |
| Second guarded reservation | 3,000 | The cash condition rejects another 7,000 reservation. No second payment request follows. |
This is a conditional illustration, not an executed benchmark or a complete application schema. Both callers reading 10,000 first provides no reservation. The runtime checks the configured condition during posting. The worker must inspect rejection and stop before calling the provider. A protected Postgres routine can enforce the same availability invariant.
- Unknown provider outcomes keep that operation's pending liability and cash reservation held.
- Definitive success permits confirmation to consume those reservations.
- Definitive failure without movement permits release to return both reservations.
- Deposits, invoices, refunds, fees and cancellations need their own reviewed accounting model.
## Coordinating Postgres, Fragment and a provider
These systems do not share an atomic transaction. Commit an immutable business command and its outbox record together in Postgres. Treat that command as pending financial acceptance. It does not establish that cash is reserved or that payment occurred.
| Phase | Application behavior |
| --- | --- |
| Reserve | Post the guarded entry using a stable command-derived ledger phase key. |
| Handle rejection | Record a visible blocked result. Make no provider request. |
| Recover an uncertain ledger acknowledgement | Recover the same logical write using supported identical-key replay. Do not create new intent. |
| Request payment | Proceed after acknowledged reservation, using a separate stable provider key. |
| Resolve provider uncertainty | Use canonical lookup or supported identical-key retry. Keep reservations while the outcome remains unknown. |
| Finalize | Confirm definitive success or release definitive failure without movement. |
Provider success followed by a ledger outage creates paid-but-unposted repair work. Repair the ledger without paying again. Persist execution progress across restarts. Business status can lag financial state, so expose pending and uncertain states honestly. This protocol does not provide cross-service exactly-once execution.
- Verify provider-event signatures and deduplicate a durable inbox.
- Bind approvals to immutable amounts, beneficiaries, destinations and expiry.
- Keep recovery workers, alerts and an exception queue.
- Restrict payment credentials and schema deployment privileges.
## Reconcile against independent evidence
Compare ledger operations against independently obtained provider records. Match identity, amount, currency and status. Track statement completeness and freshness separately from discrepancies. Balanced books or an empty report do not prove cash movement.
| Evidence | Integration reference |
| --- | --- |
| Synchronized external accounts and transactions | [Native Links and Custom Links](https://fragment.dev/guides/sync-payments.md) |
| Linked transaction reconciliation | [Reconciliation and `reconcileTx`](https://fragment.dev/guides/reconcile-payments.md) |
| Internal reservations and linked cash | Review clearing so the same movement is not counted twice. |
## Start with a reviewed model
Use integer minor units and explicit currency. Define the full accounting lifecycle before deploying. Keep operational data in Postgres and actual payment execution with the provider. Fragment's API, SDK, CLI and MCP require appropriate workspace authorization. Initial client provisioning can require an administrator.
| Next action | Reference |
| --- | --- |
| Model accounts and entry types | [Design a ledger](https://fragment.dev/guides/design-a-ledger.md) |
| Verify, deploy and post | [Ledger CLI](https://fragment.dev/api-reference/ledger-cli-commands.md), [SDKs](https://fragment.dev/api-reference/ledger-sdks.md), [posting](https://fragment.dev/guides/post-ledger-entries.md) |
| Connect agent tooling | [MCP](https://fragment.dev/api-reference/mcp.md) |
| Evaluate commercial terms | [Current pricing](https://fragment.dev/pricing) and your workspace entitlements |
Tool access does not authorize autonomous financial actions. Examples do not replace production adapters, authorization, recovery scheduling or monitoring. This comparison makes no benchmark, implementation-effort or cost-superiority claim.
## Implementation references
Use the current API contracts when implementing the architecture:
- [Post ledger entries](https://fragment.dev/guides/post-ledger-entries.md) and [configure consistency](https://fragment.dev/guides/configure-consistency.md).
- [Make payments](https://fragment.dev/guides/make-payments.md) and [reconcile transactions](https://fragment.dev/guides/reconcile-payments.md).
- [API overview](https://fragment.dev/api-reference/ledger-overview.md).
- [MCP](https://fragment.dev/api-reference/mcp.md), [CLI](https://fragment.dev/api-reference/ledger-cli-commands.md) and [SDKs](https://fragment.dev/api-reference/ledger-sdks.md).
- [Current pricing](https://fragment.dev/pricing).