This project is not covered by Drupal’s security advisory policy.
Content Relay keeps content in sync from one Drupal site, the origin, to any number of other sites, the replicas, without database dumps or shared databases. Every change travels as a signed, optionally encrypted event carrying a full snapshot of the item, identified by UUID only, with a hash either side can recompute to prove a copy matches.
Use it to run regional or language sites from one editorial site, to feed a separately hosted site from a central one, or anywhere content is written once and published in several places.
Features
- Pair sites with a one-time code. The replica enters the origin's HTTPS address and a short code; the sites exchange keys and agree on a signed contract of what the replica receives. A replica can take content from several origins, and an origin can feed many replicas.
- Signed, verifiable delivery. Every message is signed with Ed25519 and can be encrypted end to end. Each item carries a canonical hash, so either site can check that a copy is exact.
- Reliable by design. Changes are recorded inside the save transaction and delivered from cron in order, with retries, backoff and a replayable event log. Nothing is lost while a replica is down, and saves never wait for one.
- Any content entity. Nodes, media, taxonomy terms, menu links, paragraphs and custom entity types, with their translations, references and files. An item that references something not there yet is applied as soon as it arrives.
- Files included. Files used by synced content follow it, are checked by checksum, and can be encrypted in transit.
- Choose what each replica gets. Pick bundles and languages per replica, keep languages back on the origin, and choose per item whether it syncs to every replica, to none, or to all except some.
- Local edits are respected. Replicas detect local changes. An update from the origin either becomes a new revision, keeping the edit in the one before and flagging the item for review, or is refused, as configured; pulls never replace local edits. Fields can be marked local-only, and items or single translations can be detached.
- Different structures welcome. Import a bundle as it is, or map the origin's fields onto a different bundle on the replica.
- See where everything stands. Status reports on both sides show what is in sync, pending, failed or in conflict, with bulk push, pull, reconciliation and retry.
- Drush throughout. Pairing, key generation, push, pull, validation, reconciliation, failures and unpairing all have Drush commands.
Modules
content_relay: shared base (event format, serialization, hashing, signing, keys).content_relay_origin: publishes changes to replicas.content_relay_replica: receives and applies changes.
A site enables the origin, the replica, or both.
Requirements
- Drupal 10.3 or 11, PHP 8.3 or later.
- The Key module. Private keys are kept outside the database and configuration.
- HTTPS on every site.
- The PHP
sodiumextension is strongly recommended; without it a slower pure-PHP implementation is used. - Cron running on every site.
Getting started
- On each site:
composer require drupal/content_relay. - Create a signing key outside the web root, for example
drush content-relay:generate-key signing site_signing ../private/keys/signing.key. - Enable
content_relay_originon the origin andcontent_relay_replicaon each replica. - On the origin, choose the bundles to publish and generate a pairing code under Configuration » Web services » Content Relay origin.
- On the replica, pair under Configuration » Web services » Content Relay replica with the origin's address and the code.
The README covers every setting, the message format, conflicts, languages, files and troubleshooting.
Similar projects
- Entity Share lets a site pull content from another site over JSON:API, chosen by an editor. Content Relay pushes every change automatically, keeps replicas continuously in sync, and verifies each copy by hash.
Project information
- Project categories: Developer tools, Integrations, Multilingual
- Created by sean_e_dietrich on , updated
This project is not covered by the security advisory policy.
Use at your own risk! It may have publicly disclosed vulnerabilities.
Releases
Development version: 1.x-dev updated 29 Oct 2026 at 05:29 UTC
