Main context for Sync module.
Provides peer-to-peer data sync between PhoenixKit instances. Supports sync between dev↔prod, dev↔dev, or even different websites.
Programmatic API
This module provides a complete API for programmatic data sync, suitable for use from code, scripts, or AI agents.
System Control
enabled?/0- Check if Sync module is enabledenable_system/0- Enable Sync moduledisable_system/0- Disable Sync moduleget_config/0- Get current configuration and stats
Session Management (for LiveView UI)
create_session/1- Create a new sync session with connection codeget_session/1- Get session by codevalidate_code/1- Validate and mark code as useddelete_session/1- Delete a session
Local Database Inspection
list_tables/0- List all syncable tables with row countsget_schema/1- Get schema (columns, types) for a tableget_count/1- Get exact row count for a tabletable_exists?/1- Check if a table exists locallyexport_records/2- Export records from a table with pagination
Data Import
import_records/3- Import records into a table with conflict strategycreate_table/2- Create a table from a schema definition
Remote Operations (via Client)
For connecting to a remote sender and fetching data, use PhoenixKit.Modules.Sync.Client:
{:ok, client} = PhoenixKit.Modules.Sync.Client.connect("https://example.com", "ABC12345")
{:ok, tables} = PhoenixKit.Modules.Sync.Client.list_tables(client)
{:ok, records} = PhoenixKit.Modules.Sync.Client.fetch_records(client, "users")
PhoenixKit.Modules.Sync.Client.disconnect(client)Usage Examples
# List local tables
{:ok, tables} = PhoenixKit.Modules.Sync.list_tables()
# => [{name: "users", estimated_count: 150}, ...]
# Get table schema
{:ok, schema} = PhoenixKit.Modules.Sync.get_schema("users")
# => %{table: "users", columns: [...], primary_key: ["id"]}
# Export records with pagination
{:ok, records} = PhoenixKit.Modules.Sync.export_records("users", limit: 100, offset: 0)
# Import records with conflict strategy
{:ok, result} = PhoenixKit.Modules.Sync.import_records("users", records, :skip)
# => %{created: 5, updated: 0, skipped: 3, errors: []}
# Full sync workflow
{:ok, client} = PhoenixKit.Modules.Sync.Client.connect(url, code)
{:ok, tables} = PhoenixKit.Modules.Sync.Client.list_tables(client)
{:ok, result} = PhoenixKit.Modules.Sync.Client.transfer(client, "users", strategy: :skip)
Summary
Functions
Creates a new transfer session tied to the calling process.
Creates a table from a schema definition.
Deletes a session by code.
Disables the Sync module.
Enables the Sync module.
Checks if the Sync module is enabled.
Exports records from a table with pagination.
Gets the Sync module configuration with statistics.
Gets the exact row count for a table.
Gets the current incoming connection mode.
Gets the incoming connection password (if set). Returns nil if not set.
Gets the schema (columns, types, constraints) for a specific table.
Gets a session by its connection code.
Imports records into a table with conflict resolution.
Checks if an incoming connection password is set.
Lists all transferable tables in the local database with row counts.
Sets the incoming connection mode.
Sets the incoming connection password. Pass nil or empty string to clear the password.
Checks if a table exists in the local database.
Updates session status and metadata.
Validates a connection code and marks it as used if valid.
Validates an incoming connection password.
Functions
Creates a new transfer session tied to the calling process.
The session remains valid as long as the owner process (typically a LiveView) is alive. When the process terminates, the session is automatically deleted.
Parameters
direction- Either:sendor:receiveowner_pid- The PID of the owning process (defaults to self())
Returns
{:ok, session}- Session withcode,direction,status,owner_pid{:error, reason}- If creation failed
Examples
{:ok, session} = PhoenixKit.Modules.Sync.create_session(:receive)
# => %{
# code: "A7X9K2M4",
# direction: :receive,
# status: :pending,
# owner_pid: #PID<0.123.0>,
# created_at: ~U[2025-12-16 12:15:00Z]
# }
Creates a table from a schema definition.
Used when receiving data for a table that doesn't exist locally.
The schema definition should match the format returned by get_schema/1.
Examples
schema = %{
"columns" => [
%{"name" => "id", "type" => "bigint", "nullable" => false, "primary_key" => true},
%{"name" => "email", "type" => "character varying", "nullable" => false}
],
"primary_key" => ["id"]
}
:ok = PhoenixKit.Modules.Sync.create_table("users", schema)
@spec delete_session(String.t()) :: :ok
Deletes a session by code.
Disables the Sync module.
Enables the Sync module.
@spec enabled?() :: boolean()
Checks if the Sync module is enabled.
Exports records from a table with pagination.
Options
:offset- Number of records to skip (default: 0):limit- Maximum records to return (default: 100)
Examples
{:ok, records} = PhoenixKit.Modules.Sync.export_records("users", limit: 50, offset: 0)
# => [%{"id" => 1, "email" => "user@example.com", ...}, ...]
@spec get_config() :: map()
Gets the Sync module configuration with statistics.
Returns a map with:
enabled- Whether the module is enabledactive_sessions- Number of active sessions (sessions tied to LiveView processes)incoming_mode- How incoming connections are handledincoming_password_set- Whether a password is set for incoming connections
@spec get_count( String.t(), keyword() ) :: {:ok, non_neg_integer()} | {:error, any()}
Gets the exact row count for a table.
Examples
{:ok, count} = PhoenixKit.Modules.Sync.get_count("users")
# => 150
@spec get_incoming_mode() :: String.t()
Gets the current incoming connection mode.
Modes:
"auto_accept"- Automatically accept and activate incoming connections"require_approval"- Accept but set as pending, requires manual approval"require_password"- Require password before accepting"deny_all"- Reject all incoming connection requests
Default is "require_approval".
@spec get_incoming_password() :: String.t() | nil
Gets the incoming connection password (if set). Returns nil if not set.
Gets the schema (columns, types, constraints) for a specific table.
Examples
{:ok, schema} = PhoenixKit.Modules.Sync.get_schema("users")
# => %{
# table: "users",
# columns: [
# %{name: "id", type: "bigint", nullable: false, primary_key: true},
# %{name: "email", type: "character varying", nullable: false},
# ...
# ],
# primary_key: ["id"]
# }
Gets a session by its connection code.
Sessions remain valid as long as the owning LiveView process is alive. When the page is closed, the session is automatically deleted.
Returns {:ok, session} if found, {:error, :not_found} otherwise.
@spec import_records(String.t(), [map()], atom()) :: {:ok, PhoenixKit.Modules.Sync.DataImporter.import_result()} | {:error, any()}
Imports records into a table with conflict resolution.
Conflict Strategies
:skip- Skip if record with same primary key exists (default):overwrite- Replace existing record with imported data:merge- Merge imported data with existing (keeps existing where new is nil):append- Always insert as new record with auto-generated ID
Examples
records = [%{"email" => "user@example.com", "name" => "John"}, ...]
{:ok, result} = PhoenixKit.Modules.Sync.import_records("users", records, :skip)
# => %{created: 5, updated: 0, skipped: 3, errors: []}
# Append mode (ignores primary keys, creates new records)
{:ok, result} = PhoenixKit.Modules.Sync.import_records("users", records, :append)
@spec incoming_password_set?() :: boolean()
Checks if an incoming connection password is set.
Lists all transferable tables in the local database with row counts.
Returns tables from the public schema, excluding system tables and security-sensitive tables (like session tokens).
Options
:include_phoenix_kit- Include phoenixkit* tables (default: true):exact_counts- Use exact COUNT(*) instead of estimates (default: true)
Examples
{:ok, tables} = PhoenixKit.Modules.Sync.list_tables()
# => [%{name: "users", estimated_count: 150}, %{name: "posts", estimated_count: 1200}]
Sets the incoming connection mode.
Sets the incoming connection password. Pass nil or empty string to clear the password.
Checks if a table exists in the local database.
Examples
PhoenixKit.Modules.Sync.table_exists?("users")
# => true
Updates session status and metadata.
Validates a connection code and marks it as used if valid.
This is called when a sender connects to a receiver's session. Sessions remain valid as long as the owner's LiveView process is alive.
Returns
{:ok, session}- Code is valid, session is now marked as connected{:error, :invalid_code}- Code doesn't exist (or owner closed the page){:error, :already_used}- Code was already used for a connection
Validates an incoming connection password.