This document describes bucket-level replication in MinIO, which synchronizes objects and metadata between buckets within a single deployment or across different MinIO deployments. Bucket replication enables cross-region data protection, data locality optimization, and active-active configurations where objects can be read from any target even if they don't exist locally.
Note: For multi-site replication that synchronizes IAM policies, bucket configurations, and other system-level settings across entire MinIO deployments, see Site Replication.
Bucket replication in MinIO allows objects written to a source bucket to be automatically copied to one or more remote target buckets. The system supports:
The replication subsystem operates asynchronously, queuing replication tasks and tracking their status through metadata stored with each object version.
Sources: cmd/bucket-replication.go1-1362
Replication Flow Overview
The diagram shows how replication flows through MinIO when objects are created or deleted:
mustReplicate() or checkReplicateDelete() to determine if replication is neededglobalReplicationPoolTargetClientSources: cmd/bucket-replication.go251-307 cmd/bucket-replication.go421-600 cmd/object-handlers.go405-465
Bucket replication is configured using an AWS S3-compatible replication configuration XML. The configuration is stored and managed by globalBucketMetadataSys and accessed via getReplicationConfig():
Replication targets are configured with:
Sources: cmd/bucket-replication.go84-91 cmd/bucket-replication.go93-170
When a replication configuration is added or updated, validateReplicationDestination() performs several checks:
| Validation Check | Purpose |
|---|---|
| Target bucket exists | Ensures destination is accessible |
| Object lock compatibility | Source and target must both have object lock enabled |
| Self-referential check | Prevents replication loops by checking deployment IDs |
| ARN format validation | Ensures valid replication service ARN |
| Connectivity check | Verifies target endpoint is reachable |
Sources: cmd/bucket-replication.go93-170 cmd/bucket-replication.go172-209
mustReplicate()The core decision function is mustReplicate() at cmd/bucket-replication.go253-307:
Key Parameters:
bucket: Source bucket nameobject: Object name/keymopts: Options including metadata, replication status, operation typeDecision Criteria:
ReplicationStatus=Replica are not re-replicated (except metadata-only)ReplicationRequest=true flag are skippedOutput: ReplicateDecision containing per-target decisions with:
Sources: cmd/bucket-replication.go253-307 cmd/bucket-replication.go211-249
When replicating an object, the system prepares metadata using putReplicationOpts() cmd/bucket-replication.go778-896:
Included Metadata:
Special Headers for Replication:
X-Minio-Source-ETag: Original object ETagX-Minio-Source-MTime: Original modification timeX-Minio-Replication-*: Internal replication metadataX-Amz-Bucket-Replication-Status: Set to "REPLICA"Excluded Metadata:
Sources: cmd/bucket-replication.go778-896 cmd/bucket-replication.go715-756 cmd/handler-utils.go76-115
Objects track replication status through metadata fields:
| Status | Description |
|---|---|
PENDING | Queued for replication, not yet started |
COMPLETED | Successfully replicated to target |
FAILED | Replication attempt failed |
REPLICA | Object is a replica received from another site |
These states are stored in the object's xl.meta under keys defined at cmd/bucket-replication.go60-82:
ReplicationStatus: Overall replication statusReplicationTimestamp: Last replication attempt timeReplicaStatus: Marks object as a replicaReplicaTimestamp: When replica was receivedSources: cmd/bucket-replication.go60-82
When a DELETE request is made without specifying a version ID, MinIO creates a delete marker. The system then replicates this marker to targets:
When a DELETE request includes a specific version ID, it's a permanent delete:
Replication Behavior:
VersionPurgeStatus=PendingRemoveObject() on target with version IDVersionPurgeStatus=CompleteThis ensures the version isn't permanently deleted on the source until it's confirmed deleted on all targets.
Sources: cmd/bucket-replication.go421-600 cmd/bucket-replication.go602-713 cmd/bucket-replication.go346-409
Delete operations track additional metadata:
| Metadata Key | Purpose |
|---|---|
DeleteMarkerReplicationStatus | Status of delete marker replication |
VersionPurgeStatus | Status of permanent version deletion |
VersionPurgeStatuses | Per-target purge status (for multiple targets) |
Sources: cmd/bucket-replication.go60-82
MinIO supports active-active replication where clients can read objects from either site, even if the object only exists on the remote site. This is implemented through "proxy replication":
Implementation Details:
The proxy logic at cmd/object-handlers.go412-430 works as follows:
GetObjectNInfo() returns ObjectNotFound, VersionNotFound, or ReadQuorum errorsgetProxyTargets() identifies replication targets marked as active-activeproxyGetToReplicationTarget() fetches from remoteglobalReplicationStats tracks proxy operationsHEAD Request Proxying: Similar logic at cmd/object-handlers.go824-840 proxies HEAD requests to get metadata.
Sources: cmd/object-handlers.go404-465 cmd/object-handlers.go822-840
Each object version stores replication state in its metadata:
For multi-target replication, the system tracks state per target using replicatedInfos structure:
Structure:
replicatedInfos {
Targets []replicatedTargetInfo {
Arn: "arn:minio:replication::uuid:bucket/target"
PrevReplicationStatus: "PENDING"
ReplicationStatus: "COMPLETED"
ReplicationTimestamp: time.Time
Endpoint: "target-minio.example.com"
Secure: true
}
}
This allows tracking independent replication progress to each configured target.
Sources: cmd/bucket-replication.go60-82
Different types of metadata changes track their own timestamps:
| Timestamp Key | Tracks Changes To |
|---|---|
ReplicationTimestamp | Object data replication |
TaggingTimestamp | Object tag modifications |
ObjectLockRetentionTimestamp | Retention mode/date changes |
ObjectLockLegalHoldTimestamp | Legal hold status changes |
These timestamps enable MinIO to determine which metadata is newer when bidirectional replication encounters conflicts.
Sources: cmd/bucket-replication.go68-78
When replication fails, MinIO queues the operation for retry using the MRF system:
MRF Queue Operations:
queueMRFSave() at cmd/bucket-replication.go482Sources: cmd/bucket-replication.go482-495 cmd/bucket-replication.go560
MinIO also provides a healing mechanism for replication via QueueReplicationHeal():
Triggering Conditions:
Process:
Sources: cmd/object-handlers.go460 cmd/object-handlers.go495 cmd/object-handlers.go866 cmd/object-handlers.go906
Replication targets are authenticated using:
The replication worker uses the configured credentials when making requests to remote targets.
Sources: cmd/bucket-replication.go93-170
Replication handles multiple encryption scenarios:
| Encryption Type | Replication Behavior |
|---|---|
| SSE-S3 | Object re-encrypted at target with target's keys |
| SSE-KMS | Similar to SSE-S3, target uses its own KMS |
| SSE-C | Encrypted data transferred with special headers, re-encrypted at target |
For SSE-C objects, replication includes special headers defined at cmd/handler-utils.go87-104:
X-Minio-Replication-Server-Side-Encryption-Sealed-KeyX-Minio-Replication-Server-Side-Encryption-Seal-AlgorithmX-Minio-Replication-Server-Side-Encryption-IvX-Minio-Replication-Encrypted-MultipartX-Minio-Replication-Actual-Object-SizeX-Minio-Replication-Ssec-Crc (checksum of encrypted data)Sources: cmd/bucket-replication.go778-896 cmd/handler-utils.go87-104 cmd/bucket-replication.go80-82
Replication interacts with lifecycle (ILM) rules:
Lifecycle Before Replication: When getting an object, lifecycle rules are evaluated first. If an object should expire, it may be deleted before replication status can be checked cmd/object-handlers.go472-493
Replication Configuration in Lifecycle: Lifecycle rules can check replication status before applying transitions or expiration.
Sources: cmd/object-handlers.go472-493 cmd/object-handlers.go884-905
Replication requires versioning to be enabled on both source and target buckets. The check at cmd/bucket-replication.go261 ensures objects in non-versioned prefixes are not replicated.
Versioning enables:
Sources: cmd/bucket-replication.go261-263
When both source and target have Object Lock enabled, replication includes:
Validation at cmd/bucket-replication.go128-138 ensures targets with Object Lock can receive locked objects.
Sources: cmd/bucket-replication.go128-138
Replication generates events:
| Event Type | When Generated |
|---|---|
ObjectReplicationComplete | Successful replication |
ObjectReplicationFailed | Replication failure |
ObjectReplicationNotTracked | Replication not configured or error |
These events are sent via the event notification system to configured targets (webhook, SQS, etc.).
Sources: cmd/bucket-replication.go444-456 cmd/bucket-replication.go515-527 cmd/bucket-replication.go557-599
Replication respects bandwidth limits configured per target. The globalBucketTargetSys manages these limits and throttles replication traffic accordingly.
Sources: cmd/bucket-replication.go44
Specific error codes for replication failures are defined in cmd/api-errors.go:
| Error Code | HTTP Status | Description |
|---|---|---|
ErrReplicationConfigurationNotFoundError | 404 | No replication configuration exists |
ErrRemoteDestinationNotFoundError | 400 | Target bucket doesn't exist |
ErrReplicationDestinationMissingLock | 400 | Target needs Object Lock enabled |
ErrRemoteTargetNotFoundError | 400 | Target ARN not found in configuration |
ErrReplicationRemoteConnectionError | 503 | Cannot connect to remote target |
ErrBucketRemoteIdenticalToSource | 400 | Target is same as source (loop prevention) |
ErrRemoteTargetNotVersionedError | 400 | Target bucket not versioned |
ErrReplicationSourceNotVersionedError | 400 | Source bucket not versioned |
Sources: cmd/api-errors.go127-148
Replication operations log errors using specialized functions:
replLogIf(): Logs replication errorsreplLogOnceIf(): Logs error once to avoid spamThese logging functions help track replication issues without flooding logs during persistent failures.
Sources: cmd/bucket-replication.go276 cmd/bucket-replication.go443 cmd/bucket-replication.go514
Bucket replication is configured via S3 API operations handled in cmd/bucket-handlers.go72:
| API Operation | Handler | Purpose |
|---|---|---|
PUT ?replication | PutBucketReplicationConfigHandler | Set replication rules |
GET ?replication | GetBucketReplicationConfigHandler | Retrieve current configuration |
DELETE ?replication | DeleteBucketReplicationConfigHandler | Remove replication |
Object operations check and update replication metadata:
| Operation | Replication Aspect |
|---|---|
PUT Object | Evaluates rules, queues replication |
GET Object | May proxy to target if object missing |
HEAD Object | Returns replication status headers |
DELETE Object | Replicates delete markers and purges |
POST Object (Copy) | Replication metadata handling |
Sources: cmd/object-handlers.go313-578 cmd/object-handlers.go746-983
By default, replication is asynchronous:
This provides low latency for write operations.
Targets can be configured for synchronous replication where:
The mode is determined by tgt.replicateSync flag checked at cmd/bucket-replication.go302
The globalReplicationPool manages worker goroutines that:
MinIO optimizes replication by:
Sources: cmd/bucket-replication.go302-304
Refresh this wiki