Skip to main content
Skip to main content

Scale & profiles

Zerops automatically scales your PostgreSQL service based on actual database usage. When your database needs more power, resources increase. When demand drops, resources scale down to reduce costs.

Read More

For complete scaling details across all services, see Automatic Scaling and High Availability.

How PostgreSQL scaling works

PostgreSQL services use vertical scaling to adjust CPU, RAM, and disk resources within containers based on usage patterns. Unlike runtime services, PostgreSQL does not use horizontal scaling (adding/removing containers). Instead, PostgreSQL services use deployment modes for high availability.

Scaling can briefly interrupt the service

When scaling changes the service's resources, Zerops regenerates the PostgreSQL configuration and applies it with an automatic reload. If the new values require it, the service is restarted instead: rolling through the cluster in HA mode, a short outage in single mode.

A restart is only needed when the granted RAM crosses a memory step: 256 MiB, 512 MiB, 1 GiB, 2 GiB, 4 GiB, then multiples of 8 GiB. Scaling within a step reloads only; to rule out restarts entirely, keep minRam and maxRam within one step.

Scaling profiles

A scaling profile is the starting point for a PostgreSQL service. Each profile sets two things at once:

  1. The autoscaling envelope: the default minimum/maximum CPU, RAM, and disk, plus the free-resource headroom that controls how eagerly the autoscaler reacts.
  2. The PostgreSQL configuration: memory, WAL, planner, autovacuum, and replication settings tuned for a specific workload shape.

A profile name combines a workload type with a tier, e.g. oltp-production.

Workload types

TypeTuned forNotes
OLTPTransactional workloads like web apps, APIs, order processing, and auth. Short transactions and point lookups.The default and most general-purpose type. Synchronous replication in HA.
OLAPAnalytical workloads like reporting, dashboards, and large aggregations.Larger sort/hash memory, aggressive query parallelism, higher-resolution planner statistics. Asynchronous replication in HA (synchronous commits would throttle bulk loads).
WriteHeavyHigh-volume ingestion like IoT telemetry, event logging, and metrics.Commit batching, WAL compression, and aggressive autovacuum to keep up with write volume. Synchronous replication in HA.

Available profiles

The tier part of the name sets the size of the autoscaling envelope (and, in HA, the replication topology). Which profiles you can pick depends on the deployment mode:

ProfileModeUse it for
oltp-hobbySingleSide projects, prototypes, learning. Runs hot with minimal headroom to keep costs low.
oltp-stagingSingle / HAStaging, internal tools, early-stage apps. Moderate headroom. Default for single.
oltp-productionSingle / HABusiness-critical transactional workloads. Generous headroom for traffic spikes. Default for HA.
oltp-enterpriseHA onlyHigh-throughput OLTP at scale. Highest connection limits and the most aggressive headroom.
olap-productionSingle / HAAnalytical / warehouse workloads.
writeheavy-productionSingle / HAIngestion pipelines and write-heavy workloads.
customSingle / HAOLTP-based profile that lets you override individual PostgreSQL settings. See Custom profile.
Note

In HA mode the OLTP and WriteHeavy profiles run with two synchronous standbys, so an acknowledged COMMIT survives a node failure. OLAP runs with asynchronous standbys, trading a small potential window of recent writes for ingest speed.

Setting a profile

Set the profile when you create the service in the GUI, or with the profile field in your import YAML:

zerops-import.yaml
services:
- hostname: db
type: postgresql:ha@18
profile: oltp-production

If you don't set one, the default is used (oltp-staging for single, oltp-production for HA). The profile can be changed at any time in the GUI.

Overriding the autoscaling envelope

The resource limits a profile sets are defaults. You can override any of them (CPU mode, min/max CPU/RAM/disk, and the free-resource thresholds) without switching to the custom profile, using the verticalAutoscaling block in your import YAML or the Automatic scaling configuration in the GUI. These overrides apply on top of any profile.

Custom profile

The custom profile uses the OLTP tuning as its base and additionally lets you override individual PostgreSQL configuration values through profileOverrides:

zerops-import.yaml
services:
- hostname: db
type: postgresql:single@18
profile: custom
profileOverrides:
random_page_cost: 1.1
default_statistics_target: 200
autovacuum_max_workers: 5
work_mem: 67108864 # bytes (64 MiB)
autovacuum_naptime: 120000000000 # nanoseconds (2 minutes)

Settings that Zerops derives from the container's resources or that are required for the managed cluster to operate (shared_buffers, max_connections, JIT on/off, the pooler limits, and the replication/Patroni settings) are managed automatically and cannot be overridden.

Refer to the PostgreSQL configuration documentation for the meaning and valid range of each parameter, but mind the units: override values are plain numbers, with memory/disk sizes given in bytes and durations in nanoseconds. This differs from PostgreSQL's own conventions (kB, milliseconds, seconds). The table below shows which unit each key takes.

KeyType / unitDescription
work_membytesMemory per sort/hash operation before spilling to disk
hash_mem_multiplierintegerMultiplier applied to work_mem for hash-based operations
maintenance_work_membytesMemory for maintenance operations (VACUUM, CREATE INDEX, REINDEX)
autovacuum_work_membytesMemory used by each autovacuum worker
temp_buffersbytesPer-session memory for accessing temporary tables
temp_file_limitbytesMaximum total disk space a session may use for temporary files
effective_cache_sizebytesPlanner's assumption of total cache available (shared_buffers + OS cache)
effective_io_concurrencyintegerEstimated number of concurrent disk I/O operations the storage can handle
maintenance_io_concurrencyintegerConcurrent disk I/O operations for maintenance (VACUUM, prefetch)
random_page_costnumberPlanner's estimated cost of a non-sequential page fetch
default_statistics_targetintegerDefault number of samples used by ANALYZE for column statistics
jit_above_costnumberQuery plan cost above which JIT compilation is considered
max_worker_processesintegerMaximum number of background worker processes
max_parallel_workersintegerMaximum parallel workers that can be active at one time cluster-wide
max_parallel_workers_per_gatherintegerMaximum parallel workers a single Gather node can start
max_parallel_maintenance_workersintegerMaximum parallel workers for maintenance (CREATE INDEX, VACUUM)
wal_compressionstringCompression algorithm for full-page WAL images (off/pglz/lz4/zstd)
wal_buffersbytesShared memory used to buffer WAL data not yet written to disk
wal_writer_delaynanosecondsInterval at which the WAL writer flushes WAL to disk
wal_writer_flush_afterbytesWAL bytes written before the WAL writer triggers a flush
commit_delaynanosecondsArtificial delay before a WAL flush during commit to batch concurrent commits
commit_siblingsintegerMinimum number of concurrent open transactions required for commit_delay to apply
max_wal_sizebytesSoft upper limit on WAL size that triggers a checkpoint
min_wal_sizebytesMinimum WAL size kept for future reuse before recycling segments
autovacuum_max_workersintegerMaximum autovacuum worker processes running concurrently
autovacuum_naptimenanosecondsDelay between autovacuum runs on any given database
autovacuum_vacuum_scale_factornumberFraction of table size added to the autovacuum threshold
autovacuum_analyze_scale_factornumberFraction of table size added to the auto-analyze threshold
autovacuum_vacuum_cost_delaynanosecondsCost-based delay inserted by autovacuum between I/O operations
autovacuum_vacuum_cost_limitintegerAccumulated vacuum cost at which an autovacuum worker sleeps
vacuum_cost_delaynanosecondsCost-based delay inserted by manual VACUUM between I/O operations (0 disables)
idle_in_transaction_session_timeoutnanosecondsTerminate sessions that stay idle in a transaction longer than this

Configure scaling

You can configure scaling settings:

  • During service creation - Set initial scaling parameters when creating your PostgreSQL service
  • During import - Define scaling configuration in your YAML import file using verticalAutoscaling parameters
  • After service creation - Navigate to your PostgreSQL service and select Automatic scaling configuration to modify settings

Basic settings

Scaling

CPU Mode: Choose between shared (cost-effective, variable performance) or dedicated (consistent performance, higher cost). You can change CPU mode once per hour. See pricing for costs.

Resource limits: Configure minimum and maximum resources for your PostgreSQL service:

 MinimumMaximum
CPU cores18
RAM0.25 GB48 GB
Disk1 GB250 GB
  • Lower the maximum to control costs and prevent over-scaling
  • Raise the minimum when you need guaranteed baseline performance
  • Set minimum = maximum to disable automatic scaling for that specific resource

Deployment mode (single container vs. highly available) is chosen when the service is created and cannot be changed later. See Deployment modes.

High availability

In HA mode, Zerops runs a 3-node cluster across separate physical machines, fronted by two database proxy containers (free of charge) that route traffic. When a container fails, Zerops automatically replaces it on a different machine and synchronizes data from the healthy copies.

A dedicated read-replica port (5433) lets you route read-only queries to the replicas, taking load off the primary and improving throughput. See Connection parameters and Connection ports and TLS.

Advanced settings

Start CPU cores: Determines how many CPU cores are allocated during database startup. Increase this value if your PostgreSQL service starts slowly or requires more processing power during initialization.

RAM thresholds: Help prevent out-of-memory crashes by maintaining buffer space:

  • Absolute (GB): Maintains this amount of free RAM at all times
  • Percentage: Keeps this percentage of total RAM free

Consider increasing these values if your database experiences memory-related issues.

Scaling
Read More

For detailed technical parameters and scaling behavior, see Automatic Scaling and High Availability.

Monitor usage

Navigate to your PostgreSQL service and select Service containers & Overview to view:

  • CPU, RAM, and disk usage over time
  • Historical scaling events
  • Container health status

Technical details

Zerops monitors database usage and automatically adjusts resources based on predefined thresholds and timing parameters. The scaling behavior follows the same principles as other services on the platform.

For complete technical specifications including:

  • Resource monitoring intervals and thresholds
  • Scale-up and scale-down timing parameters
  • Scaling increments and steps
  • Detailed scaling behavior patterns

See Resource Scaling Behavior in the general scaling documentation.

Common issues

Out of memory errors

  • Increase minimum free RAM settings in your scaling configuration
  • Consider raising the minimum RAM allocation
  • Check for memory-intensive queries or operations

Higher than expected costs

  • Consider lowering your maximum resource limits
  • Review scaling patterns in the monitoring dashboard

Slow database startup

  • Increase the "Start CPU cores" setting
  • Consider switching to dedicated CPU mode for consistent performance

Not utilizing HA mode effectively

  • Use port 5432 for write operations (INSERT, UPDATE, DELETE)
  • Use port 5433 for read operations (SELECT) to distribute load across replicas
  • See Connection Parameters for details

Need help? Join our Discord community for assistance!