PocketBase with PostgresSQL

repository·postgres·Indexed 41 days ago

https://github.com/fondoger/pocketbase

A fork of PocketBase that adds support for PostgreSQL (v17+), enabling horizontal scaling and realtime capabilities across multiple instances. It maintains compatibility with original PocketBase SDKs and documentation, requiring a POSTGRES_URL environment variable for operation.

Tokens
19.2K
Snippets
71
Records
99
Agent score
52%

What's inside PocketBase with PostgresSQL

  1. Apply API rules based on request context

    postgres

    In v0.22.0, you can use the @request.context rule field to apply different constraints based on the execution context of the API rule. This is useful for restricting certain actions (like user creation) to specific authentication methods.

    Supported @request.context values:

    • default
    • realtime
    • protectedFile
    • oauth2

    Example: To disallow user creation via OAuth2, use the rule: @request.context != "oauth2".

    @request.context != "oauth2"
  2. Configure API rules with multi-match and multi-valued field operators

    postgres

    In v0.11.0, PocketBase introduced support for multi-match/match-all conditions and new modifiers for API rules.

    Multi-match/Match-all

    By default, multi-valued fields (select, relation) use "at least one of" logic. To require that all values match a condition, prefix the operator with ?.

    New Rule Modifiers

    • ?=: Match-all operator for multi-valued fields.
    • :isset: Checks if a static request data field is set (e.g., @request.data.role:isset = false prevents changing a field).
    • :length: Checks the length of an arrayable field (e.g., someSelectField:length = 2).
    • :each: Used with select fields to check if all selected rows match a pattern (e.g., roles:each ~ 'pb_%').
    • .*: Allows querying relation fields via the request data (e.g., @request.data.someRel.status = "active").
    ```js
    // Match
  3. Limitations of Horizontal Scaling with PostgresSQL

    postgres

    When using multiple instances for horizontal scaling:

    • Local File System: Files are not synced across instances. You must use an S3 storage account if you need the file upload feature to work across multiple nodes.
    • Backups: The built-in SQLite Backup feature is not supported. Use mature PostgreSQL backup solutions like pg_dump, docker-pg-backup, or postgres-backup-s3.
  4. Use back/indirect relation filter, sort, and expand

    postgres

    Starting from v0.22.0, PocketBase supports filtering, sorting, and expanding via back/indirect relations.

    To reference back relation fields, use the syntax: yourCollection_via_yourRelField.*.

    Important Constraints:

    • To prevent excessive joins, the nested relations resolver is limited to a maximum depth of 6 levels (matching the expand limit).
    • The old parenthesis syntax yourCollection(yourRelField) is soft-deprecated and will trigger a console warning; you should migrate to the _via_ syntax.
    • Naming Restriction: Collections and fields are no longer allowed to contain the string _via_ in their names to avoid collisions with this new syntax.
    // New syntax for back relations
    yourCollection_via_yourRelField.*
    
    // Deprecated syntax (still works but warns)
    yourCollection(yourRelField)
  5. Use the new structured logging system

    postgres

    As of v0.20.0, PocketBase uses a generalized logging system based on the standard Go log/slog interfaces. This replaces the previous request-only logging.

    Key Details:

    • Go usage: Use app.Logger() to log information with structured attributes.
    • JS usage: Use $app.logger() within the JSVM.
    • Performance: Logs are written in batches (every 200 logs) or after a 3-second debounce to minimize performance impact.
    • Configuration: You can set a minimum log level (e.g., -4 for debug logs) via the Admin UI.
    • Note: The _requests table has been replaced by the _logs table. Existing logs will be deleted during this transition.
    // Go
    app.Logger().Info("Example message", "total", 123, "details", "lorem ipsum...")
    // JS
    $app.logger().info("Example message", "total", 123, "details", "lorem ipsum...")
  6. Handle JSON field normalization for multipart/form-data

    postgres

    In v0.12.0, PocketBase applies specific normalization rules to json fields that are submitted as plain strings (common when using multipart/form-data). This ensures seamless compatibility between JSON and form-data requests.

    Normalization Rules:

    • "true" $\rightarrow$ true (boolean)
    • "false" $\rightarrow$ false (boolean)
    • "null" $\rightarrow$ null
    • "[1,2,3]" $\rightarrow$ [1,2,3] (array)
    • "{\"a\":1}" $\rightarrow$ {"a":1} (object)
    • Numeric strings $\rightarrow$ JSON number
    • Double quoted strings are left as-is.
    • Any other string (including empty strings) is wrapped in double quotes.

    Constraint Update: The Nonempty constraint for json fields now also checks for null, [], {}, and "" (empty string).

  7. Configure View collections with custom SQL

    postgres

    Introduced in v0.13.0, View collections allow you to create read-only collections from custom SQL SELECT statements.

    Supported features include:

    • Aggregations (COUNT(), MIN(), MAX(), GROUP BY, etc.)
    • Column and table aliases
    • CTEs and subquery expressions
    • Auto relation fields association
    • file fields proxying (up to 5 linked relations, e.g., view1 -> view2 -> ... -> base)
    • Support for filter, sort, and expand
    • List and View API rules
  8. Update PocketBase configuration initialization (v0.17.0 breaking change)

    postgres

    In version 0.17.0, several initialization functions were updated to use Config{} structs instead of *Options{} pointers. This was done to ensure configuration defaults are isolated within function calls and to improve consistency.

    When upgrading, replace pointer arguments with value arguments for the following functions:

    • pocketbase.NewWithConfig(config pocketbase.Config)
    • core.NewBaseApp(config core.BaseAppConfig)
    • apis.Serve(app core.App, config apis.ServeConfig)
    • jsvm.MustRegister(app core.App, config jsvm.Config)
    • ghupdate.MustRegister(app core.App, rootCmd *cobra.Command, config ghupdate.Config)
    • migratecmd.MustRegister(app core.App, rootCmd *cobra.Command, config migratecmd.Config)
  9. Deploy PocketBase with PostgresSQL using Docker

    postgres

    To deploy a full stack using Docker, follow these steps to set up a PostgreSQL container and then the PocketBase container.

    Note: In production, avoid using the :latest tag; use a specific version instead.

    # 1. Start PostgresSQL
    docker run -d \
      --name postgres \
      -p 5432:5432 \
      -e POSTGRES_USER=user \
      -e POSTGRES_PASSWORD=pass \
      -v ./pg_data:/var/lib/postgresql/data \
      postgres:alpine
    
    # 2. Start PocketBase
    docker run -d \
      --network=host \
      --name pocketbase \
      -v ./pb_data:/data \
      -e PB_HTTP_ADDR=127.0.0.1:8090 \
      -e PB_DATA_DIR="/data" \
      -e POSTGRES_URL="postgres://user:pass@127.0.0.1:5432/postgres?sslmode=disable" \
      ghcr.io/fondoger/pocketbase:latest
    
    # 3. Get admin password reset link
    docker logs -f pocketbase