PowerSync
PowerSync is a sync engine for local-first apps. Syncs PostgreSQL data to mobile devices and browsers with real-time replication.
Configuration
services:
postgres:
image: postgres:17-alpine
restart: unless-stopped
command: ["postgres", "-c", "wal_level=logical"]
environment:
POSTGRES_USER: powersync
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: powersync
volumes:
- postgres-data:/var/lib/postgresql/data
- ../files/init-powersync.sql:/docker-entrypoint-initdb.d/init-powersync.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U powersync -d powersync"]
interval: 5s
timeout: 5s
retries: 12
powersync:
image: journeyapps/powersync-service:1.21.0
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
POWERSYNC_CONFIG_PATH: /config/powersync.yaml
NODE_OPTIONS: --max-old-space-size=1000
volumes:
- ../files/powersync.yaml:/config/powersync.yaml:ro
command: ["start", "-r", "unified"]
volumes:
postgres-data:[variables]
main_domain = "${domain}"
# Password for the bundled PostgreSQL (used as replication source and bucket storage).
postgres_password = "${password:32}"
# Auto-generated token for the PowerSync API (used in Authorization header).
admin_token = "${password:32}"
# HS256 secret used to sign development JWTs for clients (base64url encoded).
jwks_key = "${password:48}"
[config]
[[config.domains]]
serviceName = "powersync"
port = 8080
host = "${main_domain}"
# PowerSync has no route on "/"; the liveness probe returns 200.
path = "/probes/liveness"
[config.env]
POSTGRES_PASSWORD = "${postgres_password}"
# PowerSync service configuration.
# Docs: https://docs.powersync.com/self-hosting/installation/powersync-service-setup
[[config.mounts]]
filePath = "powersync.yaml"
content = """
telemetry:
disable_telemetry_sharing: true
# Replication source: the bundled Postgres (wal_level=logical).
# Point this at your own database to sync real data.
replication:
connections:
- type: postgresql
uri: postgresql://powersync:${postgres_password}@postgres:5432/powersync
sslmode: disable
# Bucket storage. Must be a different database than the replication source.
storage:
type: postgresql
uri: postgresql://powersync:${postgres_password}@postgres:5432/powersync_storage
sslmode: disable
port: 8080
# Sync rules: syncs the demo "lists" table to all clients.
# Edit these for your own schema: https://docs.powersync.com/usage/sync-rules
sync_rules:
content: |
bucket_definitions:
global:
data:
- SELECT * FROM lists
client_auth:
# HS256 key for signing development tokens.
# See https://docs.powersync.com/installation/authentication-setup/custom
jwks:
keys:
- kty: oct
alg: HS256
kid: powersync-dev
k: ${jwks_key}
audience: ["powersync"]
api:
tokens:
- ${admin_token}
"""
# Runs once on the first Postgres startup (empty data volume).
[[config.mounts]]
filePath = "init-powersync.sql"
content = """
-- Separate database for PowerSync bucket storage.
CREATE DATABASE powersync_storage OWNER powersync;
-- Demo table synced by the default sync rules.
CREATE TABLE lists (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
name text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
INSERT INTO lists (name) VALUES ('Welcome to PowerSync');
-- Publication used by PowerSync logical replication.
CREATE PUBLICATION powersync FOR ALL TABLES;
"""Base64
To import this template in Dokploy: create a Compose service → Advanced → Base64 import and paste the content below:
ewogICJjb21wb3NlIjogInNlcnZpY2VzOlxuICBwb3N0Z3JlczpcbiAgICBpbWFnZTogcG9zdGdyZXM6MTctYWxwaW5lXG4gICAgcmVzdGFydDogdW5sZXNzLXN0b3BwZWRcbiAgICBjb21tYW5kOiBbXCJwb3N0Z3Jlc1wiLCBcIi1jXCIsIFwid2FsX2xldmVsPWxvZ2ljYWxcIl1cbiAgICBlbnZpcm9ubWVudDpcbiAgICAgIFBPU1RHUkVTX1VTRVI6IHBvd2Vyc3luY1xuICAgICAgUE9TVEdSRVNfUEFTU1dPUkQ6ICR7UE9TVEdSRVNfUEFTU1dPUkR9XG4gICAgICBQT1NUR1JFU19EQjogcG93ZXJzeW5jXG4gICAgdm9sdW1lczpcbiAgICAgIC0gcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGFcbiAgICAgIC0gLi4vZmlsZXMvaW5pdC1wb3dlcnN5bmMuc3FsOi9kb2NrZXItZW50cnlwb2ludC1pbml0ZGIuZC9pbml0LXBvd2Vyc3luYy5zcWw6cm9cbiAgICBoZWFsdGhjaGVjazpcbiAgICAgIHRlc3Q6IFtcIkNNRC1TSEVMTFwiLCBcInBnX2lzcmVhZHkgLVUgcG93ZXJzeW5jIC1kIHBvd2Vyc3luY1wiXVxuICAgICAgaW50ZXJ2YWw6IDVzXG4gICAgICB0aW1lb3V0OiA1c1xuICAgICAgcmV0cmllczogMTJcblxuICBwb3dlcnN5bmM6XG4gICAgaW1hZ2U6IGpvdXJuZXlhcHBzL3Bvd2Vyc3luYy1zZXJ2aWNlOjEuMjEuMFxuICAgIHJlc3RhcnQ6IHVubGVzcy1zdG9wcGVkXG4gICAgZGVwZW5kc19vbjpcbiAgICAgIHBvc3RncmVzOlxuICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeVxuICAgIGVudmlyb25tZW50OlxuICAgICAgUE9XRVJTWU5DX0NPTkZJR19QQVRIOiAvY29uZmlnL3Bvd2Vyc3luYy55YW1sXG4gICAgICBOT0RFX09QVElPTlM6IC0tbWF4LW9sZC1zcGFjZS1zaXplPTEwMDBcbiAgICB2b2x1bWVzOlxuICAgICAgLSAuLi9maWxlcy9wb3dlcnN5bmMueWFtbDovY29uZmlnL3Bvd2Vyc3luYy55YW1sOnJvXG4gICAgY29tbWFuZDogW1wic3RhcnRcIiwgXCItclwiLCBcInVuaWZpZWRcIl1cblxudm9sdW1lczpcbiAgcG9zdGdyZXMtZGF0YTpcbiIsCiAgImNvbmZpZyI6ICJbdmFyaWFibGVzXVxubWFpbl9kb21haW4gPSBcIiR7ZG9tYWlufVwiXG4jIFBhc3N3b3JkIGZvciB0aGUgYnVuZGxlZCBQb3N0Z3JlU1FMICh1c2VkIGFzIHJlcGxpY2F0aW9uIHNvdXJjZSBhbmQgYnVja2V0IHN0b3JhZ2UpLlxucG9zdGdyZXNfcGFzc3dvcmQgPSBcIiR7cGFzc3dvcmQ6MzJ9XCJcbiMgQXV0by1nZW5lcmF0ZWQgdG9rZW4gZm9yIHRoZSBQb3dlclN5bmMgQVBJICh1c2VkIGluIEF1dGhvcml6YXRpb24gaGVhZGVyKS5cbmFkbWluX3Rva2VuID0gXCIke3Bhc3N3b3JkOjMyfVwiXG4jIEhTMjU2IHNlY3JldCB1c2VkIHRvIHNpZ24gZGV2ZWxvcG1lbnQgSldUcyBmb3IgY2xpZW50cyAoYmFzZTY0dXJsIGVuY29kZWQpLlxuandrc19rZXkgPSBcIiR7cGFzc3dvcmQ6NDh9XCJcblxuW2NvbmZpZ11cbltbY29uZmlnLmRvbWFpbnNdXVxuc2VydmljZU5hbWUgPSBcInBvd2Vyc3luY1wiXG5wb3J0ID0gODA4MFxuaG9zdCA9IFwiJHttYWluX2RvbWFpbn1cIlxuIyBQb3dlclN5bmMgaGFzIG5vIHJvdXRlIG9uIFwiL1wiOyB0aGUgbGl2ZW5lc3MgcHJvYmUgcmV0dXJucyAyMDAuXG5wYXRoID0gXCIvcHJvYmVzL2xpdmVuZXNzXCJcblxuW2NvbmZpZy5lbnZdXG5QT1NUR1JFU19QQVNTV09SRCA9IFwiJHtwb3N0Z3Jlc19wYXNzd29yZH1cIlxuXG4jIFBvd2VyU3luYyBzZXJ2aWNlIGNvbmZpZ3VyYXRpb24uXG4jIERvY3M6IGh0dHBzOi8vZG9jcy5wb3dlcnN5bmMuY29tL3NlbGYtaG9zdGluZy9pbnN0YWxsYXRpb24vcG93ZXJzeW5jLXNlcnZpY2Utc2V0dXBcbltbY29uZmlnLm1vdW50c11dXG5maWxlUGF0aCA9IFwicG93ZXJzeW5jLnlhbWxcIlxuY29udGVudCA9IFwiXCJcIlxudGVsZW1ldHJ5OlxuICBkaXNhYmxlX3RlbGVtZXRyeV9zaGFyaW5nOiB0cnVlXG5cbiMgUmVwbGljYXRpb24gc291cmNlOiB0aGUgYnVuZGxlZCBQb3N0Z3JlcyAod2FsX2xldmVsPWxvZ2ljYWwpLlxuIyBQb2ludCB0aGlzIGF0IHlvdXIgb3duIGRhdGFiYXNlIHRvIHN5bmMgcmVhbCBkYXRhLlxucmVwbGljYXRpb246XG4gIGNvbm5lY3Rpb25zOlxuICAgIC0gdHlwZTogcG9zdGdyZXNxbFxuICAgICAgdXJpOiBwb3N0Z3Jlc3FsOi8vcG93ZXJzeW5jOiR7cG9zdGdyZXNfcGFzc3dvcmR9QHBvc3RncmVzOjU0MzIvcG93ZXJzeW5jXG4gICAgICBzc2xtb2RlOiBkaXNhYmxlXG5cbiMgQnVja2V0IHN0b3JhZ2UuIE11c3QgYmUgYSBkaWZmZXJlbnQgZGF0YWJhc2UgdGhhbiB0aGUgcmVwbGljYXRpb24gc291cmNlLlxuc3RvcmFnZTpcbiAgdHlwZTogcG9zdGdyZXNxbFxuICB1cmk6IHBvc3RncmVzcWw6Ly9wb3dlcnN5bmM6JHtwb3N0Z3Jlc19wYXNzd29yZH1AcG9zdGdyZXM6NTQzMi9wb3dlcnN5bmNfc3RvcmFnZVxuICBzc2xtb2RlOiBkaXNhYmxlXG5cbnBvcnQ6IDgwODBcblxuIyBTeW5jIHJ1bGVzOiBzeW5jcyB0aGUgZGVtbyBcImxpc3RzXCIgdGFibGUgdG8gYWxsIGNsaWVudHMuXG4jIEVkaXQgdGhlc2UgZm9yIHlvdXIgb3duIHNjaGVtYTogaHR0cHM6Ly9kb2NzLnBvd2Vyc3luYy5jb20vdXNhZ2Uvc3luYy1ydWxlc1xuc3luY19ydWxlczpcbiAgY29udGVudDogfFxuICAgIGJ1Y2tldF9kZWZpbml0aW9uczpcbiAgICAgIGdsb2JhbDpcbiAgICAgICAgZGF0YTpcbiAgICAgICAgICAtIFNFTEVDVCAqIEZST00gbGlzdHNcblxuY2xpZW50X2F1dGg6XG4gICMgSFMyNTYga2V5IGZvciBzaWduaW5nIGRldmVsb3BtZW50IHRva2Vucy5cbiAgIyBTZWUgaHR0cHM6Ly9kb2NzLnBvd2Vyc3luYy5jb20vaW5zdGFsbGF0aW9uL2F1dGhlbnRpY2F0aW9uLXNldHVwL2N1c3RvbVxuICBqd2tzOlxuICAgIGtleXM6XG4gICAgICAtIGt0eTogb2N0XG4gICAgICAgIGFsZzogSFMyNTZcbiAgICAgICAga2lkOiBwb3dlcnN5bmMtZGV2XG4gICAgICAgIGs6ICR7andrc19rZXl9XG4gIGF1ZGllbmNlOiBbXCJwb3dlcnN5bmNcIl1cblxuYXBpOlxuICB0b2tlbnM6XG4gICAgLSAke2FkbWluX3Rva2VufVxuXCJcIlwiXG5cbiMgUnVucyBvbmNlIG9uIHRoZSBmaXJzdCBQb3N0Z3JlcyBzdGFydHVwIChlbXB0eSBkYXRhIHZvbHVtZSkuXG5bW2NvbmZpZy5tb3VudHNdXVxuZmlsZVBhdGggPSBcImluaXQtcG93ZXJzeW5jLnNxbFwiXG5jb250ZW50ID0gXCJcIlwiXG4tLSBTZXBhcmF0ZSBkYXRhYmFzZSBmb3IgUG93ZXJTeW5jIGJ1Y2tldCBzdG9yYWdlLlxuQ1JFQVRFIERBVEFCQVNFIHBvd2Vyc3luY19zdG9yYWdlIE9XTkVSIHBvd2Vyc3luYztcblxuLS0gRGVtbyB0YWJsZSBzeW5jZWQgYnkgdGhlIGRlZmF1bHQgc3luYyBydWxlcy5cbkNSRUFURSBUQUJMRSBsaXN0cyAoXG4gIGlkIHV1aWQgUFJJTUFSWSBLRVkgREVGQVVMVCBnZW5fcmFuZG9tX3V1aWQoKSxcbiAgbmFtZSB0ZXh0IE5PVCBOVUxMLFxuICBjcmVhdGVkX2F0IHRpbWVzdGFtcHR6IE5PVCBOVUxMIERFRkFVTFQgbm93KClcbik7XG5cbklOU0VSVCBJTlRPIGxpc3RzIChuYW1lKSBWQUxVRVMgKCdXZWxjb21lIHRvIFBvd2VyU3luYycpO1xuXG4tLSBQdWJsaWNhdGlvbiB1c2VkIGJ5IFBvd2VyU3luYyBsb2dpY2FsIHJlcGxpY2F0aW9uLlxuQ1JFQVRFIFBVQkxJQ0FUSU9OIHBvd2Vyc3luYyBGT1IgQUxMIFRBQkxFUztcblwiXCJcIlxuIgp9Links
Tags
sync, database, local-first, postgresql, realtime
Version: 1.21.0