Skip to main content
Buckets are a way to isolate different ledgers within the same database server. This is useful when you want to separate data for different clients, or different applications, or different environments.

Understanding PostgreSQL Schemas

At a technical level, a bucket in Formance is directly mapped to a PostgreSQL schema. In PostgreSQL, a schema is a namespace that groups together database objects (tables, views, indexes, functions):
  • Without schemas: All tables would live in one big global namespace, which could quickly become messy
  • With schemas: You can organize and separate data logically, avoid name collisions, and apply different permissions
Two tables with the same name can exist in different schemas, as they live under different namespaces.

How Formance Uses Schemas

When you create a ledger, Formance stores its data inside a PostgreSQL schema (the bucket). This has several implications:
AspectDescription
IsolationEach bucket/schema provides clean separation of ledger data. Two ledgers in different buckets won’t share tables, reducing risk of accidental data mixing.
Shared storage within a bucketMultiple ledgers inside the same bucket share the same underlying tables, which can be efficient but means their data is less isolated.
Scaling strategyBy using multiple buckets, you can spread data across different schemas to avoid a single schema growing too large and becoming a performance bottleneck.

System Schema

Formance uses a special internal schema called _system to track metadata about your ledgers and buckets.
If you ever delete a bucket manually in PostgreSQL (via DROP SCHEMA), you must also remove the corresponding entry in the _system schema. Skipping this step can leave your ledger registry in an inconsistent state.

Practical Considerations

  • Data Isolation: Buckets are a good fit if you need strong separation (e.g., per-tenant ledgers in a multi-tenant system)
  • Performance Management: For high-volume workloads, spreading ledgers across multiple buckets can reduce contention and keep queries fast
  • Simplicity: If isolation isn’t critical, sticking with the _default bucket keeps things straightforward

Creating a bucket

Buckets are automatically created when you create a new ledger. By default, if the bucket is not specified, the ledger is created in the _default bucket. Using fctl, you can specify the bucket when creating a new ledger:
fctl ledger create <ledger-name> --bucket <bucket-name>
Alternatively, to create a ledger on a specific bucket, use the command:
curl -X POST http://localhost:3068/v2/testing -d '{"bucket": "bucket0"}'
curl http://localhost:3068/v2/testing | jq
{
  "data": {
    "bucket": "bucket0",
    "metadata": {},
    "features": {
      "ACCOUNT_METADATA_HISTORY": "SYNC",
      "HASH_LOGS": "SYNC",
      "MOVES_HISTORY": "ON",
      "MOVES_HISTORY_POST_COMMIT_EFFECTIVE_VOLUMES": "SYNC",
      "TRANSACTION_METADATA_HISTORY": "SYNC"
    },
    "id": 2,
    "name": "testing",
    "addedAt": "2024-10-03T08:27:11.540373Z"
  }
}

Features

Each usage of the ledger service is different. Some usage involves high write throughput, while others involve high read throughput, custom aggregation, etc. So, each ledger can be configured with a set of features. By default, when creating a ledger, all features are enabled. To create a ledger with specific features, use the command:
curl -X POST http://localhost:3068/v2/testing2 -d '{"features": {"HASH_LOGS": "DISABLED"}}'
curl http://localhost:3068/v2/testing2 | jq
{
  "data": {
    "bucket": "_default",
    "metadata": {},
    "features": {
      "ACCOUNT_METADATA_HISTORY": "SYNC",
      "HASH_LOGS": "DISABLED",
      "MOVES_HISTORY": "ON",
      "MOVES_HISTORY_POST_COMMIT_EFFECTIVE_VOLUMES": "SYNC",
      "TRANSACTION_METADATA_HISTORY": "SYNC"
    },
    "id": 3,
    "name": "testing2",
    "addedAt": "2024-10-03T08:40:40.545233Z"
  }
}
When overriding features, all not specified features will receive the default configuration.
Current set of features is not stable, some can be added or removed.

Current set of features

NameDefault valuePossible configurationDescription
ACCOUNT_METADATA_HISTORYSYNCSYNC | DISABLEDHistorize metadata changes on accounts
TRANSACTION_METADATA_HISTORYSYNCSYNC | DISABLEDHistorize metadata changes on transactions
HASH_LOGSSYNCSYNC | DISABLEDHash logs
MOVES_HISTORYONON | OFFHistorize funds movements by account
MOVES_HISTORY_POST_COMMIT_EFFECTIVE_VOLUMESSYNCSYNC | DISABLEDCompute and maintains post commit effective volumes