Skip to main content
Version: Weekly Build

PostgreSQL

PostgreSQL is a general-purpose relational database for transactional workloads, application state, and structured analytics. In the current provider definitions, this provider is GA.

PropertyValueNotes
Provider namepostgresUse this in landscape provider definitions.
Versionv1Current schema version exposed by the provider.
CategoryDatabaseShown in the managed services catalog.
ScopeglobalAvailable at resource group scope rather than being tied to a single workspace runtime.
Resource group singletonfalseResource groups can create multiple PostgreSQL service instances.
Pause supporttrueThis provider supports pausing.

Capabilities​

CapabilitySupportedNotes
Backups✅Backups of the database are supported.
Point-in-time recovery✅The database can be restored to a specific point in time.
Good to know
  • Upgrades are never applied automatically. Manual minor version upgrades are supported via the version config field.
  • Storage does not grow automatically, but you can increase the storage plan parameter manually at any time.

Architecture​

Each PostgreSQL service is a dedicated PostgreSQL server running on Codesphere's Kubernetes infrastructure, powered by the CloudNativePG operator. Codesphere manages the full lifecycle: provisioning, configuration changes, minor version updates, volume resizing, and recovery from backups.

  • Dedicated instance: Your database runs in its own pod with its own persistent volume. Nothing is shared with other services or resource groups.
  • Storage: Data is stored on Ceph block storage (RBD), which is replicated at the storage layer.
  • Backups: Backups are continuously archived to object storage, which enables both restoring a specific backup and point-in-time recovery.
  • Container image: Codesphere ships its own PostgreSQL images, based on the CloudNativePG images, with the extensions listed below preinstalled.
  • Single instance: A service with a single instance has no replicas, so configuration updates, version upgrades, and platform updates cause a short downtime. See Shutdown behavior.
  • High availability: With three instances, restarts cause only a short interruption. See Shutdown behavior.

Schema​

Config​

FieldTypeRequired on createNotes
versionstringNoPostgreSQL engine version. Default: 17.9. Allowed values: 17.9, 17.6, 16.13, 16.10, 15.17, 15.14, 14.22, 14.19. Minor upgrades only.
userNamestringNoDefault: app. Immutable after creation. Cannot be postgres.
databaseNamestringNoDefault: app. Immutable after creation.

Secrets​

FieldTypeRequired on createNotes
userPasswordstringYesPassword for the application user defined by userName.
superuserPasswordstringYesPassword for the postgres superuser.

Details / Output​

FieldTypeAvailabilityNotes
hostnamestringExposed after provisioningInternal service hostname.
portintegerExposed after provisioningPostgreSQL port.
dsnstringExposed after provisioningConnection string returned by the provider.
readybooleanExposed after provisioningIndicates whether the instance is ready for connections.

Plan​

The provider exposes one plan, Small (id: 0). Example plan: Small (id: 0).

ParameterTypeDefaultMinimumMaximumStaticNotes
cpunumber1--YesPriced as cpu-tenths.
memoryinteger128--YesPriced as ram-mib.
storageinteger1024512-NoPriced as storage-mib.

Example in a Landscape​

schemaVersion: v0.2

run:
app-db:
provider:
name: postgres
version: v1
plan:
id: 0
parameters:
storage: 2048
config:
version: "17.9"
userName: "${{ workspace.env.PGUSER }}"
databaseName: "${{ workspace.env.PGDATABASE }}"
secrets:
userPassword: "${{ vault.pgUserPassword }}"
superuserPassword: "${{ vault.pgSuperuserPassword }}"

Constructing Hostnames​

Landscape-managed service hostnames are deterministic and follow this structure:

ms-{providerName}-{providerVersion}-{resourceGroupId}-landscape-{workspaceId}-{serviceName}.rg-{resourceGroupId}

The hostname is converted to lowercase and any invalid characters are replaced with hyphens.

Older services use the ms-postgres suffix instead, for example ms-postgres-v1-42-landscape-100-db.ms-postgres.

This change is not breaking: new services are also reachable through an alias with the ms-postgres suffix, so existing configurations and scripts that use .ms-postgres hostnames keep working.

If your PostgreSQL service is named db, the hostname can be constructed as ms-postgres-v1-$TEAM_ID-landscape-$WORKSPACE_ID-db.rg-$TEAM_ID in shell commands or as ms-postgres-v1-${{ resourceGroup.id }}-landscape-${{ workspace.id }}-db.rg-${{ resourceGroup.id }} in landscape templates.

ProviderVersionResource Group IDWorkspace IDService NameHostname
postgresv142100dbms-postgres-v1-42-landscape-100-db.rg-42

Example ci.yml using the constructed hostname directly in a command:

schemaVersion: v0.2

run:
db:
provider:
name: postgres
version: v1
plan:
id: 0
parameters:
storage: 2048
config:
version: "17.9"
secrets:
userPassword: "${{ vault.pgUserPassword }}"
superuserPassword: "${{ vault.pgSuperuserPassword }}"

api:
steps:
- command: >
psql "postgres://app:${PG_PASSWORD}@ms-postgres-v1-$TEAM_ID-landscape-$WORKSPACE_ID-db.rg-$TEAM_ID:5432/app" -c "select 1"
env:
PG_PASSWORD: "${{ vault.pgUserPassword }}"

Example ci.yml using the constructed hostname through an environment variable:

schemaVersion: v0.2

run:
db:
provider:
name: postgres
version: v1
plan:
id: 0
parameters:
storage: 2048
config:
version: "17.9"
secrets:
userPassword: "${{ vault.pgUserPassword }}"
superuserPassword: "${{ vault.pgSuperuserPassword }}"

api:
steps:
- command: >
psql "postgres://app:${PG_PASSWORD}@${PG_HOST}:5432/app" -c "select 1"
env:
PG_HOST: ms-postgres-v1-${{ resourceGroup.id }}-landscape-${{ workspace.id }}-db.rg-${{ resourceGroup.id }}
PG_PASSWORD: "${{ vault.pgUserPassword }}"

Within application runtimes, connect with the returned dsn or with hostname, port, the configured username, and the stored password. The same internal endpoint can also be used from other Codesphere runtimes, including reactives, managed containers, and workloads running inside a Virtual Cluster.

Connecting to a Postgres DB​

Prerequisites​

Once your Postgres DB is deployed, you can connect to it from your Codesphere workspaces. Each service lists its non-sensitive connection details on its settings page in the overview tab (or in the details property of the public API payload).

info

Before connecting, make sure the service is synchronized and running: in the service settings, ready must be true.

Connecting via Terminal (psql)​

You can use the psql command-line tool directly from your workspace terminal.

# Install psql
nix-env -iA nixpkgs.postgresql

# General syntax
psql "postgres://<username>@<hostname>:5432/<database>" -W

# Example
psql "postgres://[email protected]:5432/mydb" -W

Connecting via Node.js​

Using the pg library:

const { Client } = require('pg');

const client = new Client({
connectionString: 'postgres://admin:[email protected]:5432/mydb'
});

await client.connect();
const res = await client.query('SELECT $1::text as message', ['Hello Codesphere!']);
console.log(res.rows[0].message); // Hello Codesphere!
await client.end();

Backups​

The PostgreSQL provider supports automated backups and point-in-time recovery to any S3-compatible backup store. This section contains the PostgreSQL-specific configuration; the general concepts are covered in Managed Service Backups.

Under the hood, backups are implemented with the CloudNativePG Barman Cloud plugin: it takes periodic physical base backups of the database and continuously archives the write-ahead log (WAL) to the configured backup store. A recovery restores a base backup and replays the archived WAL on top of it — this is what enables point-in-time recovery between two backups.

Enabling Backups​

The following example enables backups on an existing PostgreSQL service. The same backups block also works when creating a new service with POST /managed-services.

curl -X PATCH "https://api.codesphere.com/managed-services/YOUR_SERVICE_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"backups": {
"enabled": true,
"intervalH": 12,
"deleteRetentionDays": 30,
"config": {
"endpointUrl": "https://s3.eu-central-1.amazonaws.com",
"destinationPath": "s3://my-codesphere-backups/",
"accessKey": "YOUR_S3_ACCESS_KEY"
},
"secrets": {
"secretKey": "YOUR_S3_SECRET_KEY"
}
}
}'
warning

The endpointUrl must be the regional S3 endpoint, not a bucket-specific hostname. For example, https://s3.eu-central-1.amazonaws.com instead of https://my-bucket.s3.eu-central-1.amazonaws.com.

Required S3 Permissions​

The credentials (access key and secret key) used to access your S3-compatible backup store must have sufficient permissions to create, read, update, and delete objects. For AWS S3, this means the IAM user or role associated with your access key must have the following minimum permissions.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BucketLevelOperations",
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:ListBucketMultipartUploads"
],
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME"
},
{
"Sid": "ObjectLevelOperations",
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:DeleteObject",
"s3:GetObject",
"s3:ListMultipartUploadParts",
"s3:PutObject",
"s3:PutObjectTagging"
],
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*"
}
]
}

Recovery Examples​

Restoring a backup always creates a new managed service; the existing service remains untouched.

Point-in-Time Recovery​

Specify the previous managed service ID (msId) together with a recovery timestamp (time):

curl -X POST "https://api.codesphere.com/managed-services" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"resourceGroupId": 123,
"name": "my-postgres-recovered",
"provider": {
"name": "postgres",
"version": "v1"
},
"plan": {
"id": 0,
"parameters": { "storage": 2048 }
},
"config": {
"version": "17.9"
},
"secrets": {
"userPassword": "secure-password",
"superuserPassword": "secure-superuser-password"
},
"recoverFrom": {
"msId": "OLD_MANAGED_SERVICE_ID",
"time": "2026-04-10T12:00:00Z",
"config": {
"endpointUrl": "https://s3.eu-central-1.amazonaws.com",
"destinationPath": "s3://my-codesphere-backups/",
"accessKey": "YOUR_S3_ACCESS_KEY"
},
"secrets": {
"secretKey": "YOUR_S3_SECRET_KEY"
}
}
}'

Recover from a Specific Backup​

Alternatively, recover from a specific backupId:

curl -X POST "https://api.codesphere.com/managed-services" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"resourceGroupId": 123,
"name": "my-postgres-recovered",
"provider": {
"name": "postgres",
"version": "v1"
},
"plan": {
"id": 0,
"parameters": { "storage": 2048 }
},
"config": {
"version": "17.9"
},
"secrets": {
"userPassword": "secure-password",
"superuserPassword": "secure-superuser-password"
},
"recoverFrom": {
"id": "BACKUP_UUID_HERE",
"config": {
"endpointUrl": "https://s3.eu-central-1.amazonaws.com",
"destinationPath": "s3://my-codesphere-backups/",
"accessKey": "YOUR_S3_ACCESS_KEY"
},
"secrets": {
"secretKey": "YOUR_S3_SECRET_KEY"
}
}
}'

Backup storage and WAL archiving​

Backups write two kinds of data to the backup store:

  • Base backups are full copies of the database, taken every intervalH hours.
  • WAL (write-ahead log) is archived continuously, starting with the first base backup.

Both are compressed with gzip. Disabling backups stops both base backups and WAL archiving. Existing backups stay in the bucket.

Sizing the backup store​

Backups older than deleteRetentionDays are deleted, together with the WAL that only they needed. Plan the bucket for roughly:

compressed base backup size × (deleteRetentionDays × 24 / intervalH)
+ compressed WAL written during deleteRetentionDays

Each base backup is roughly the size of your database, reduced by compression.

warning

Use a separate bucket and quota for each managed service. If several databases share one quota, one write-heavy database can fill it and stop backups for all of them.

If your backup store is a Codesphere Object Storage service, its limits (maxSizeKb, maxObjects) apply to all of its buckets together. Separate buckets in the same service still share one quota, so create one Object Storage service per database.

What happens when the backup store is full​

PostgreSQL keeps WAL on the database's disk until it is archived. If archiving fails, for example because the bucket is full, WAL builds up on the disk. When the disk is full, PostgreSQL stops and the service becomes unavailable.

To prevent this, keep enough free space in the bucket. If archiving fails, free up space or lower deleteRetentionDays. Archiving then catches up and the WAL is removed from the disk.

Storage only grows​

You can increase a service's storage, but you can't decrease it.

Backup Disclaimers and Limitations​

The following limitations and requirements apply specifically to backing up and recovering PostgreSQL databases:

  • Transaction Required: To recover a Postgres database, there needs to be at least one database transaction that occurred.
  • Prior Backup Required: There must be at least one completed backup before your desired target recovery time.
  • WAL-File Timing: The target recovery time must be before the latest transaction in the latest Write-Ahead Log (WAL) file. Note that it can take a few minutes for the latest WAL-file to be saved to the backup storage bucket.
  • Version Compatibility: Recovering a backup using a different database version than the original backup is not guaranteed to work.
  • Credentials Must Match: When recovering, you cannot change the database users, database name, and passwords to something other than what was originally stored in the backup.

Extensions​

The PostgreSQL image ships with a set of extensions, including PostGIS for spatial data and pgvector for vector similarity search. All extensions listed below are available on every instance, however they are not active until you enable them.

Enabling an Extension​

Extensions are enabled per database with CREATE EXTENSION. Connect to the target database as the postgres superuser and run:

-- Enable an extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Verify which extensions are installed
SELECT extname, extversion FROM pg_extension;

-- Disable an extension again
DROP EXTENSION "uuid-ossp";

You can list all available extensions and their versions directly from your instance:

SELECT name, default_version, installed_version FROM pg_available_extensions ORDER BY name;

Available Extensions​

ExtensionVersionDescription
address_standardizer3.6.0Parse an address into constituent elements, generally used to support geocoding address normalization.
address_standardizer_data_us3.6.0Address Standardizer US dataset example.
amcheck1.4Functions for verifying relation integrity.
autoinc1.0Functions for autoincrementing fields.
bloom1.0Bloom access method — signature file based index.
btree_gin1.3Support for indexing common datatypes in GIN.
btree_gist1.7Support for indexing common datatypes in GiST.
citext1.6Data type for case-insensitive character strings.
cube1.5Data type for multidimensional cubes.
dblink1.2Connect to other PostgreSQL databases from within a database.
dict_int1.0Text search dictionary template for integers.
dict_xsyn1.0Text search dictionary template for extended synonym processing.
earthdistance1.2Calculate great-circle distances on the surface of the Earth.
file_fdw1.0Foreign-data wrapper for flat file access.
fuzzystrmatch1.2Determine similarities and distance between strings.
hstore1.8Data type for storing sets of (key, value) pairs.
insert_username1.0Functions for tracking who changed a table.
intagg1.1Integer aggregator and enumerator (obsolete).
intarray1.5Functions, operators, and index support for 1-D arrays of integers.
isn1.2Data types for international product numbering standards.
lo1.1Large Object maintenance.
ltree1.3Data type for hierarchical tree-like structures.
moddatetime1.0Functions for tracking last modification time.
pageinspect1.12Inspect the contents of database pages at a low level.
pg_buffercache1.5Examine the shared buffer cache.
pg_freespacemap1.2Examine the free space map (FSM).
pg_prewarm1.2Prewarm relation data.
pg_stat_statements1.11Track planning and execution statistics of all SQL statements executed.
pg_surgery1.0Extension to perform surgery on a damaged relation.
pg_trgm1.6Text similarity measurement and index searching based on trigrams.
pg_visibility1.2Examine the visibility map (VM) and page-level visibility info.
pg_walinspect1.1Functions to inspect contents of the PostgreSQL Write-Ahead Log.
pgaudit17.1Provides auditing functionality.
pgcrypto1.3Cryptographic functions.
pgrowlocks1.2Show row-level locking information.
pgstattuple1.5Show tuple-level statistics.
plpgsql1.0PL/pgSQL procedural language. Installed by default.
postgis3.6.0PostGIS geometry and geography spatial types and functions.
postgis_raster3.6.0PostGIS raster types and functions.
postgis_sfcgal3.6.0PostGIS SFCGAL functions.
postgis_tiger_geocoder3.6.0PostGIS TIGER geocoder and reverse geocoder.
postgis_topology3.6.0PostGIS topology spatial types and functions.
postgres_fdw1.1Foreign-data wrapper for remote PostgreSQL servers.
refint1.0Functions for implementing referential integrity (obsolete).
seg1.4Data type for representing line segments or floating-point intervals.
sslinfo1.2Information about SSL certificates.
tablefunc1.0Functions that manipulate whole tables, including crosstab.
tcn1.0Triggered change notifications.
tsm_system_rows1.0TABLESAMPLE method which accepts number of rows as a limit.
tsm_system_time1.0TABLESAMPLE method which accepts time in milliseconds as a limit.
unaccent1.1Text search dictionary that removes accents.
uuid-ossp1.1Generate universally unique identifiers (UUIDs).
vector0.8.1Vector data type and ivfflat and hnsw access methods (pgvector).
xml21.1XPath querying and XSLT.

Shutdown behavior​

The database is shut down and restarted from time to time, for example for configuration changes, image updates, or platform updates. How the PostgreSQL service behaves depends on its number of instances.

Single instance​

With a single instance, the database stops and starts again. Your data stays on the persistent volume and is not affected by the restart.

The downtime depends on whether clients keep their connections open when the shutdown starts. The database stops accepting new connections right away and gives existing connections up to 180 seconds to close on their own. After that, the remaining connections are closed.

SituationBehaviorApproximate downtime
All clients disconnect shortly after the shutdown startsThe database stops cleanly without waiting.About 1 minute
At least one client keeps its connection openThe database waits 180 seconds, then closes the remaining connections.About 4 minutes

New connections are refused from the moment the shutdown starts. This means the database is unavailable for new clients for the whole duration, even while existing connections are still working.

Applications with a connection pool usually keep long-lived connections and do not disconnect on their own. Expect the longer case for these applications.

High availability (three instances)​

With three instances, the service runs one primary and two replicas. The instances are spread across nodes where possible.

When the primary is shut down, the service switches over to a replica. The old primary is stopped right away without waiting for open connections, and a replica takes over as the new primary.

SituationBehaviorApproximate downtime
The primary is shut downA replica takes over as primary. Existing connections are closed right away.About 10 to 20 seconds

Clients must reconnect after the switchover. Applications that retry failed connections recover on their own.

Data safety​

  • Committed transactions are safe.
  • Transactions that are still open when connections are closed are rolled back. Clients receive a connection error and must retry.
  • With three instances, the old primary is stopped cleanly before a replica is promoted, so the new primary has all committed data.