s3sync 1.54.2

Reliable, flexible, and fast synchronization tool for S3.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
# s3sync

[![Crates.io](https://img.shields.io/crates/v/s3sync.svg)](https://crates.io/crates/s3sync)
[![crates.io downloads](https://img.shields.io/crates/d/s3sync.svg)](https://crates.io/crates/s3sync)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
![MSRV](https://img.shields.io/badge/msrv-1.88.0-red)
![CI](https://github.com/nidor1998/s3sync/actions/workflows/ci.yml/badge.svg?branch=main)
[![codecov](https://codecov.io/gh/nidor1998/s3sync/branch/main/graph/badge.svg?token=GO3DGS2BR4)](https://codecov.io/gh/nidor1998/s3sync)
[![dependency status](https://deps.rs/crate/s3sync/latest/status.svg)](https://deps.rs/crate/s3sync/)

## Table of contents

<details>
<summary>Click to expand to view table of contents </summary>

- [Overview]#Overview
- [Features]#Features
    * [Object integrity check]#Object-Integrity-Check
    * [Multiple ways]#Multiple-Ways
    * [Fast]#Fast
    * [Any object size support]#Any-object-size-support
    * [Low memory usage]#Low-memory-usage
    * [Easy to use]#Easy-to-use
    * [Robust retry logic]#Robust-retry-logic
    * [Metadata support]#Metadata-support
    * [Tagging support]#Tagging-support
    * [SSE support]#SSE-support
    * [Flexible filtering]#Flexible-filtering
    * [User-defined metadata filtering]#User-defined-metadata-filtering
    * [Tagging filtering]#Tagging-filtering
    * [Incremental transfer]#Incremental-transfer
    * [ETag-based incremental transfer]#Etag-based-incremental-transfer
    * [Additional checksum-based incremental transfer]#Additional-checksum-based-incremental-transfer
    * [Proxy support]#Proxy-support
    * [Amazon S3 Express One Zone support]#Amazon-S3-Express-One-Zone-support
    * [Versioning support]#Versioning-support
    * [Point-in-time snapshot]#Point-in-time-snapshot
    * [Server-side copy support]#Server-side-copy-support
    * [Full object checksum support]#Full-object-checksum-support
    * [Rate limiting by objects/bandwidth]#Rate-limiting-by-objectsbandwidth
    * [Sync statistics report]#Sync-statistics-report
    * [--delete support]#--delete-support
    * [Etag-based conditional write/delete support]#Etag-based-conditional-writedelete-support
    * [Lua scripting support]#Lua-scripting-support
    * [User-defined preprocessing callback]#User-defined-preprocessing-callback
    * [User-defined event callback]#User-defined-event-callback
    * [User-defined filter callback]#User-defined-filter-callback
- [Requirements]#Requirements
- [License]#License
- [Installation]#Installation
    * [Install Rust]#Install-Rust
    * [Build]#Build
    * [As a Rust library]#As-A-Rust-Library
- [Usage]#Usage
    * [Local to S3]#Local-to-S3
    * [S3 to Local]#S3-to-Local
    * [S3 to S3]#S3-to-S3
    * [S3 to S3 server-side copy]#S3-to-S3-server-side-copy
    * [Specify access key/secret access key]#Specify-access-keysecret-access-key
    * [Specify profile]#Specify-profile
    * [Specify region]#Specify-region
    * [Versioning mode]#Versioning-mode
    * [Custom endpoint]#Custom-endpoint
    * [Amazon S3 Transfer Acceleration]#Amazon-S3-Transfer-Acceleration
    * [Amazon S3 Multi-Region Access Points]#Amazon-S3-Multi-Region-Access-Points
    * [Amazon S3 Access Points]#Amazon-S3-Access-Points
    * [Dry run mode]#Dry-run-mode
    * [--delete mode]#--delete-mode
- [Detailed information]#Detailed-information
    * [Object integrity check detail]#Object-integrity-check-detail
    * [--auto-chunksize option]#--auto-chunksize-option
    * [Retry logic detail]#Retry-logic-detail
    * [Filtering order]#Filtering-order
    * [Incremental transfer detail]#Incremental-transfer-detail
    * [Versioning support detail]#Versioning-support-detail
    * [Versioning and point-in-time snapshot]#Versioning-and-point-in-time-snapshot
    * [Metadata support detail]#Metadata-support-detail
    * [Website redirect location]#Website-redirect-location
    * [Memory usage detail]#Memory-usage-detail
    * [Parallel object listing]#Parallel-object-listing
    * [--max-parallel-listing-max-depth option]#--max-parallel-listing-max-depth-option
    * [S3 Permissions]#S3-Permissions
        + [Source bucket]#Source-Bucket
        + [Target bucket]#Target-Bucket
    * [Lua VM]#Lua-VM
    * [Lua VM security]#Lua-VM-security
    * [Lua script error]#Lua-script-error
    * [Lua version]#Lua-version
    * [CLI process exit codes]#CLI-process-exit-codes

- [Advanced options]#Advanced-options
    * [--worker-size]#--worker-size
    * [--max-parallel-uploads]#--max-parallel-uploads
    * [--force-retry-count]#--force-retry-count
    * [--remove-modified-filter]#--remove-modified-filter
    * [--filter-include-regex/--filter-exclude-regex]#--filter-include-regex--filter-exclude-regex
    * [--check-etag]#--check-etag
    * [--put-last-modified-metadata]#--put-last-modified-metadata
    * [--additional-checksum-algorithm]#--additional-checksum-algorithm
    * [--enable-additional-checksum]#--enable-additional-checksum
    * [--disable-multipart-verify]#--disable-multipart-verify
    * [-v]#-v
    * [--aws-sdk-tracing]#--aws-sdk-tracing
    * [--auto-complete-shell]#--auto-complete-shell
    * [-h/--help]#-h--help

- [All command line options]#All-command-line-options

</details>

## Overview

s3sync is a reliable, flexible, and fast synchronization tool for S3.  
It serves as an alternative to the AWS CLI’s `aws s3 sync` command, offering more powerful features and better
performance.

It can be used to synchronize local directories with an S3 bucket and synchronize between S3 buckets as well.  
It supports multipart uploads, versioning, metadata, and tagging.

This tool is designed solely for object storage (S3 or S3-compatible) data synchronization.

### Demo

`c8i.xlarge (4 vCPU, 8 GB)` with 180 workers, local to S3, 50,000 objects (10 KiB each)

This demo shows the integrity check features (MD5 and SHA256) and performance (4,300 objects/sec).  
The final command performs an incremental transfer based on modification time, enabling fast incremental transfers.

![demo](media/demo.webp)

## Features

### Object integrity check

s3sync calculates ETag(MD5 or equivalent) for each object and compares them with the ETag in the target.  
An object on the local disk is read from the disk and compared with the checksum in the source or
target.  
Even if the source object was uploaded with multipart upload, s3sync can calculate and compare ETag for each part and
the entire object.   
With `--auto-chunksize` option, s3sync automatically calculates the correct chunk size for multipart upload (But it will
need more API calls and time).  
In the case of S3 to S3, s3sync simply compares ETags that are calculated by S3.  
Optionally, s3sync can also calculate and compare additional checksum (SHA256/SHA1/CRC32/CRC32C/CRC64NVME) for each
object.  
If you want to obtain evidence of the integrity check, you can use `-vv` option to output the verification information.

  ```bash
  $ s3sync -vv --additional-checksum-algorithm SHA256 ./30 s3://xxxxx |rg '(verified|sync completed)'
  2025-07-11T00:48:43.946290Z DEBUG e_tag verified. key="30/30Mib.dat" source_e_tag="\"a81230a7666d413e511f9c2c2523947a-4\"" target_e_tag="\"a81230a7666d413e511f9c2c2523947a-4\""
  2025-07-11T00:48:43.946298Z DEBUG additional checksum verified. key="30/30Mib.dat" additional_checksum_algorithm="SHA256" target_checksum="5NrHBc0Z1wNCbADRDy8mJaIvc53oxncCrw/Fa48VhxY=-4" source_checksum="5NrHBc0Z1wNCbADRDy8mJaIvc53oxncCrw/Fa48VhxY=-4"
  2025-07-11T00:48:43.946319Z  INFO sync completed. key="30Mib.dat" source_version_id="" source_last_modified="2025-06-17T06:19:54.483+00:00" target_key="30/30Mib.dat" size=31457280
  30.00 MiB | 22.47 MiB/sec,  transferred   1 objects | 0 objects/sec,  etag verified 1 objects,  checksum verified 1 objects,  deleted 0 objects,  skipped 0 objects,  error 0 objects, warning 0 objects,  duration 1 second
  $
  ```

Note: Amazon S3 Express One Zone does not support ETag as verification. But s3sync uses additional checksum algorithm
for verification by default(CRC64NVME).

### Multiple ways

- Local to S3(S3-compatible storage)
- S3(S3-compatible storage) to Local
- S3 to S3(cross-region, same-region, same-account, cross-account, from-to S3/S3-compatible storage)

### Fast

s3sync is implemented in Rust and uses the AWS SDK for Rust, which supports multithreaded asynchronous I/O.  
In my environment(`c7a.xlarge`, with 160 workers), uploading from local to S3 achieved about 4,300 objects/sec (small
objects 10KiB),  
The following are benchmark results on a
`s3sync 1.45.0(glibc)/c7a.xlarge(4vCPU, 8GB)/200GB IOPS SSD(io 1)/Amazon Linux 2023 AMI` instance on AWS in
`ap-northeast-1`. No special optimizations were applied to the instance, the network, or the S3 topology.  
You can reproduce the benchmark with the following commands.

Note: The default s3sync setting uses `--worker-size 16` and `--max-parallel-uploads 16`. This is a moderate setting for
most cases. If you want to improve performance, you can increase `--worker-size` and `--max-parallel-uploads`. But it
will increase CPU and memory usage.

Note: Increasing `--worker-size` and `--max-parallel-uploads` is not always beneficial. This depends on factors such as
instance type, network, data size, and number of objects.

Local to S3, `c7a.xlarge(4vCPU, 8GB)` 100,000 objects(10KiB objects), 976.56 MiB | 41.96 MiB/sec, 23 seconds, and all
objects are end-to-end integrity verified(MD5, SHA256).

  ```
  [ec2-user@aws-c7a-xlarge s3sync]$ time s3sync --worker-size 160 --additional-checksum-algorithm SHA256 ./test_data s3://2ef073f2-f779-4361-956d-052ad0e6e79b/test_data
  976.56 MiB | 41.96 MiB/sec,  transferred 100000 objects | 4,297 objects/sec,  etag verified 100000 objects,  checksum verified 100000 objects,  deleted 0 objects,  skipped 0 objects,  error 0 objects, warning 0 objects,  duration 23 seconds

  real    0m23.287s
  user    0m31.859s
  sys     0m22.800s
  ```

Local to S3, `c7a.xlarge(4vCPU, 8GB)` 16 objects(6GiB each), 96.00 GiB | 256.72 MiB/sec, 6.23 minutes, and all
objects are end-to-end integrity verified(MD5, SHA256).

Note: Calculating ETag/additional checksum is costly with large local objects.

Note: Above the case, the bottleneck is the disk I/O (Maximum throughput is 500MB/s).

  ```
  [ec2-user@aws-c7a-xlarge s3sync]$ time s3sync --max-parallel-uploads 48 --additional-checksum-algorithm SHA256 ./test_data s3://2ef073f2-f779-4361-956d-052ad0e6e79b/test_data
  96.00 GiB | 256.72 MiB/sec,  transferred  16 objects | 0 objects/sec,  etag verified 16 objects,  checksum verified 16 objects,  deleted 0 objects,  skipped 0 objects,  error 0 objects, warning 0 objects,  duration 6 minutes

  real    6m23.024s
  user    7m26.504s
  sys     1m45.131s
  ```

S3 to Local, `c7a.xlarge(4vCPU, 8GB)` 16 objects(6GiB each), 96.00 GiB | 166.63 MiB/sec, 10 minutes, and all objects
are end-to-end integrity verified(MD5, SHA256).  
ETag/additional checksum verification is costly in the case of S3 to Local. Because s3sync needs to read the entire
downloaded object from the local disk to calculate ETag/checksum.   
You can disable it with `--disable-etag-verify` and remove `--enable-additional-checksum`. Without all verifications,
the result was 96.00 GiB | 505.33 MiB/sec, 3.2 minutes.

Note: Above the case, the bottleneck is the disk I/O (Maximum throughput is 500MB/s).

  ```
  [ec2-user@aws-c7a-xlarge s3sync]$ time s3sync --max-parallel-uploads 48 --enable-additional-checksum s3://2ef073f2-f779-4361-956d-052ad0e6e79b/ ./download/
  96.00 GiB | 166.63 MiB/sec,  transferred  16 objects | 0 objects/sec,  etag verified 16 objects,  checksum verified 16 objects,  deleted 0 objects,  skipped 0 objects,  error 0 objects, warning 0 objects,  duration 10 minutes

  real    9m50.060s
  user    7m55.742s
  sys     2m23.921s
  ```

### Any object size support

s3sync can handle any object size. From 0 bytes to 50TiB.  
Multipart upload is used for objects larger than `--multipart-threshold`(default:8MiB).

### Low memory usage

Memory usage is low and does not depend on the object size or number of objects.
It mainly depends on the number of workers/max parallel uploads count and multipart chunk size.  
The default setting uses about 1.2GB of maximum memory for any object size or number of objects.

### Easy to use

s3sync is designed to be easy to use.  
s3sync has over 100 command line options, this is because there are many use cases.  
But the default settings are reasonable for most cases of reliable synchronization.

For example, In an IAM role environment, the following command will transfer all objects from the local directory to
the S3 bucket and verify the integrity of the transferred objects using ETag(MD5 or equivalent).  
If something goes wrong, s3sync will display a warning or error message to help you understand the issue.

  ```bash
  s3sync /path/to/local s3://bucket-name/prefix
  ```

### Robust retry logic

For long-running operations, s3sync has a robust original retry logic in addition to AWS SDK's retry logic.

For more information, see [Retry logic detail](#Retry-logic-detail).

### Metadata support

All metadata of the object can be synchronized. For example, `Content-Type`, `Content-Encoding`, `Cache-Control`,
user-defined metadata, etc.

### Tagging support

All tags of the object can be synchronized.

### SSE support

The following SSE modes are supported.

- SSE-S3
- SSE-KMS
- SSE-C
- DSSE-KMS

### Flexible filtering

- Key, `ContentType`, user-defined metadata and tagging by regular expression.
- Size and modified time
- Custom filtering with a Lua script or User-defined callback function (Rust)

### User-defined metadata filtering

You can filter objects based on user-defined metadata.  
The regular expression syntax is the same as [fancy_regex](https://docs.rs/fancy-regex/latest/fancy_regex/#syntax).  
Example: `--filter-include-metadata-regex 'key1=(value1|xxx),key2=value2'`,
`--filter-exclude-metadata-regex 'key1=(value1|xxx),key2=value2'`

Note: When using this option, Additional API calls may be required to get the metadata of each object.

### Tagging filtering

You can filter objects based on tags.  
The regular expression syntax is the same as [fancy_regex](https://docs.rs/fancy-regex/latest/fancy_regex/#syntax).  
This crate supports lookaround features.

For example, `'^(?!.*&test=true).*stage=first'` can be used to filter objects that do not contain `test=true` and that
contain `stage=first` in the tags.  
And you can also create regular expressions that combine multiple logical conditions with lookaround features.  
This feature reduces the need for Lua scripts or custom callback Rust codes (see below) to filter objects with complex
patterns.

Note: When using this option, Additional API calls are required to get the tags of each object.

### Incremental transfer

This is the default behavior.  
Transfer only modified objects. If the object modification time is newer than the target object, the object is
transferred.
Incremental transfer can be resumed from the last checkpoint.
Checking of modified objects is fast (In my environment, it takes about 1 second per 25,000 objects).

### ETag-based incremental transfer

If you want ETag-based incremental transfer, you can use `--check-etag` option.  
It compares the ETag of the source object with the ETag of the target object and transfers only modified objects.  
ETag is not always MD5. If the object is uploaded with multipart upload, ETag is not MD5 digest but the MD5 digest of
these concatenated values.
By default, s3sync uses `multipart-threshold`(default:8MiB) and `multipart-chunksize`(default:8MiB) and calculate ETag
for each part based on these values.  
With `--auto-chunksize`, s3sync can calculate and compare ETag for each part and the entire object based on the correct
chunk size. It is useful if you don't know the correct chunk size. But it will need more API calls and time. See
`--auto-chunksize` option.  
With `--dry-run`, you can check the synchronization status without transferring the objects.  
With `--json-tracing`, you can output the tracing information in JSON format.

  ```bash
  s3sync -vv --dry-run --check-etag --auto-chunksize testdata/ s3://XXXX/testdata/
  2024-06-15T01:23:50.632072Z DEBUG object filtered. ETags are same. name="HeadObjectChecker" source_e_tag="da6a0d097e307ac52ed9b4ad551801fc" target_e_tag="da6a0d097e307ac52ed9b4ad551801fc" source_last_modified="2024-06-15T01:01:48.687+00:00" target_last_modified="2024-06-15T01:02:27+00:00" source_size=6291456 target_size=6291456 key="dir1/data2.dat"
  2024-06-15T01:23:50.675831Z DEBUG object filtered. ETags are same. name="HeadObjectChecker" source_e_tag="d126ef08817d0490e207e456cb0ae080-2" target_e_tag="d126ef08817d0490e207e456cb0ae080-2" source_last_modified="2024-06-15T01:01:48.685+00:00" target_last_modified="2024-06-15T01:02:27+00:00" source_size=9437184 target_size=9437184 key="dir1/data1.dat"
  2024-06-15T01:23:50.683417Z DEBUG object filtered. ETags are same. name="HeadObjectChecker" source_e_tag="ebe97f2a4738800fe71edbe389c000a6-2" target_e_tag="ebe97f2a4738800fe71edbe389c000a6-2" source_last_modified="2024-06-15T01:01:48.690+00:00" target_last_modified="2024-06-15T01:02:27+00:00" source_size=12582912 target_size=12582912 key="dir1/data3.dat"
  0 B | 0 B/sec,  transferred   0 objects | 0 objects/sec,  etag verified 0 objects,  checksum verified 0 objects,  deleted 0 objects,  skipped 3 objects,  error 0 objects, warning 0 objects,  duration 0 seconds
  ```

With `--check-mtime-and-etag` option, s3sync first checks the modification time, then ETag of the source and target
objects. It
is useful if you want to transfer only modified objects based on the modification time and ETag.

Note: Calculating ETag is costly with local objects. Because s3sync needs to read the entire object from the local disk
to calculate ETag.

### Additional checksum-based incremental transfer

If you use Amazon S3 with additional checksum(SHA256/SHA1/CRC32/CRC32C/CRC64NVME), you can use
`--check-additional-checksum` option.  
This option compares the checksum of both source and target objects and transfers only modified objects. It costs
extra API calls per object.  
with `--dry-run`, you can check the synchronization status without transferring the objects.  
with `--json-tracing`, you can output the tracing information in JSON format.

  ```bash
  s3sync -vv --dry-run --check-additional-checksum SHA256 --additional-checksum-algorithm SHA256 testdata/ s3://XXXX/testdata/
  2024-06-15T01:06:30.035362Z DEBUG object filtered. Checksums are same. name="HeadObjectChecker" checksum_algorithm="SHA256" source_checksum="tp2uVqFNGoMU7UBmTEAz6gpVDuomc+BN9CpmrGufryw=" target_checksum="tp2uVqFNGoMU7UBmTEAz6gpVDuomc+BN9CpmrGufryw=" source_last_modified="2024-06-15T01:01:48.687+00:00" target_last_modified="2024-06-15T01:02:27+00:00" source_size=6291456 target_size=6291456 key="dir1/data2.dat"
  2024-06-15T01:06:30.041354Z DEBUG object filtered. Checksums are same. name="HeadObjectChecker" checksum_algorithm="SHA256" source_checksum="zWifJvli3SaQ9LZtHxzpOjkUE9x4ovgJZ+34As/NMwc=-2" target_checksum="zWifJvli3SaQ9LZtHxzpOjkUE9x4ovgJZ+34As/NMwc=-2" source_last_modified="2024-06-15T01:01:48.685+00:00" target_last_modified="2024-06-15T01:02:27+00:00" source_size=9437184 target_size=9437184 key="dir1/data1.dat"
  2024-06-15T01:06:30.086455Z DEBUG object filtered. Checksums are same. name="HeadObjectChecker" checksum_algorithm="SHA256" source_checksum="MyTyVYvNthXQp4fOwy/IzuKgFGIzIHpP1DiTfjZoV0Q=-2" target_checksum="MyTyVYvNthXQp4fOwy/IzuKgFGIzIHpP1DiTfjZoV0Q=-2" source_last_modified="2024-06-15T01:01:48.690+00:00" target_last_modified="2024-06-15T01:02:27+00:00" source_size=12582912 target_size=12582912 key="dir1/data3.dat"
  0 B | 0 B/sec,  transferred   0 objects | 0 objects/sec,  etag verified 0 objects,  checksum verified 0 objects,  deleted 0 objects,  skipped 3 objects,  error 0 objects, warning 0 objects,  duration 0 seconds
  ```

With `--check-mtime-and-additional-checksum` option, s3sync first checks the modification time, then additional checksum
of the
source and target objects. It is useful if you want to transfer only modified objects based on the modification time and
additional checksum.

Note: Calculating additional checksum is costly with local objects. Because s3sync needs to read the entire object from
the local disk to calculate the checksum.

### Proxy support

s3sync supports for proxy environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY`).   
s3sync automatically respects these proxy environment variables.

Proxy authentication is supported. Like `http(s)://user:password@proxy:port` .

### Amazon S3 Express One Zone support

s3sync can be used
with [Amazon S3 Express One Zone](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-Endpoints.html).

s3sync does not depend on the sorting order of returned objects of ListObjectsV2 API.  
s3sync gathers all objects in the target bucket at first step (not concurrently) and stores the information with Map.

In S3 Express One Zone, ETag is not MD5. So, s3sync uses additional checksum algorithm for verification by default(
CRC64NVME).

### Versioning support

All versions of the object can be synchronized. (Except intermediate delete markers)  
To enable versioning, use `--enable-versioning` option.

### Point-in-time snapshot

With a versioning-enabled S3 bucket, you can transfer objects at a specific point in time.

### Server-side copy support

When transferring from S3 to S3 (same region), server-side copy (CopyObject/UploadPartCopy) is a good choice.  
Server-side copy is fast and does not transfer data over the network.
If you transfer S3 to S3(cross-region or different object storage), you cannot use server-side copy.

### Full object checksum support

with `--full-object-checksum`, s3sync can use full object checksum(CRC32/CRC32C/CRC64NVME) for each object.

For more information,
see [Checking object integrity in Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html).

### Rate limiting by objects/bandwidth

For example, you can limit the number of objects transferred per second to 1,000, and the bandwidth to 100MB/sec.

### Sync statistics report

s3sync can check and report the synchronization status at any time.  
It only checks the synchronization status without transferring any objects.  
For example, If you want to check whether all objects transferred by the AWS CLI were transferred correctly (checksum
based),
the following command will show the report.

  ```bash
  aws s3 sync test_data s3://xxxx/
  s3sync --check-additional-checksum CRC64NVME --json-tracing --report-sync-status test_data s3://xxxx/ |tail -2 |jq
  ```

The following is an example of the report (the last two lines of the above command).

  <details>
  <summary>Click to expand to view report </summary>

  ```json
  {
  "timestamp": "2025-07-17T22:41:51.457601Z",
  "level": "INFO",
  "fields": {
    "name": "SYNC_STATUS",
    "type": "CHECKSUM",
    "status": "MATCHES",
    "key": "dir7/data4.dat",
    "checksum_algorithm": "CRC64NVME",
    "source_checksum": "YE4jTLSB/cA=",
    "target_checksum": "YE4jTLSB/cA=",
    "source_version_id": "",
    "target_version_id": "",
    "source_last_modified": "2025-06-14T03:52:21.843+00:00",
    "target_last_modified": "2025-07-17T22:40:51+00:00",
    "source_size": 22020096,
    "target_size": 22020096
  }
}
{
  "timestamp": "2025-07-17T22:41:51.473349Z",
  "level": "INFO",
  "fields": {
    "name": "REPORT_SUMMARY",
    "number_of_objects": 40,
    "etag_matches": 0,
    "checksum_matches": 40,
    "metadata_matches": 0,
    "tagging_matches": 0,
    "not_found": 0,
    "etag_mismatch": 0,
    "checksum_mismatch": 0,
    "metadata_mismatch": 0,
    "tagging_mismatch": 0,
    "etag_unknown": 0,
    "checksum_unknown": 0
  }
}
  ```

  </details>

You can check the synchronization status of the object's tagging and metadata with `--report-metadata-sync-status` and
`--report-tagging-sync-status` options.

Note: For reporting, s3sync uses a special process exit code. `0` If all objects are synchronized correctly. `3` If some
objects are not synchronized correctly.

Note: It needs additional API calls to get the metadata, checksum, and tags of each object.

### --delete support

Objects that exist in the target but not in the source are deleted during synchronization.  
Exclude filters other than `--filter-exclude-regex` will not prevent an object from being deleted.  
Since this can cause data loss, test first with the `--dry-run` option.

With `--max-delete`, you can limit the maximum number of deletions for safety.

### Etag-based conditional write/delete support

You can use `--if-match` for conditional write and delete operations(PutObject/CompleteMultipartUpload/DeleteObject)
with `If-Match` header.
And you can use `--copy-source-if-match` for conditional copy operations(CopyObject/UploadPartCopy) with
`x-amz-copy-source-if-match` header.

Actually, it serves as like optimistic locking.  
This prevents race conditions that s3sync overwrites or deletes an object that has been modified by another process
after s3sync checks the object.

`--if-none-match` option is also available.  
This option guarantees that the object does not exist in the target bucket. Without this option, race conditions can
occur.

If precondition fails, s3sync skips the object and outputs a warning message.  
If you want to treat it as an error, you can use `--warn-as-error` option.

It is a challenging topic to understand, please refer
to [AWS document](https://docs.aws.amazon.com/AmazonS3/latest/userguide/conditional-requests.html)

Note: few S3-compatible storage supports conditional requests.

### Lua scripting support

You can use a [Lua](https://www.lua.org) (5.4) script to implement custom filtering, event handling, preprocessing
before transferring objects
to S3.  
`--preprocess-callback-lua-script`, `--event-callback-lua-script`, `--filter-callback-lua-script` options are available
for this purpose.  
Lua is widely recognized as a fast scripting language. The Lua engine is embedded in s3sync, so you can use Lua script
without any additional dependencies.  
For example, you can use Lua script to implement custom preprocessing logic, such as dynamically modifying the object
attributes(e.g., metadata, tagging) before transferring it to S3.  
By default, Lua scripts run in safe mode, so they cannot use Lua’s OS or I/O library functions.  
If you want to allow more Lua libraries, you can use `--allow-lua-os-library`, `--allow-lua-unsafe-vm` option.  
With Lua third-party C libraries, you can use more complex logic, like querying databases, requesting web APIs, etc.

See [Lua script example](https://github.com/nidor1998/s3sync/tree/main/src/lua/script/)

Note: `--preprocess-callback-lua-script` can not modify the object's key or content itself.

### User-defined preprocessing callback

This feature is for advanced users not satisfied with the default Lua scripting.  
If you are familiar with Rust, you can use `UserDefinedPreprocessCallback` to dynamically modify the object attributes(
e.g. metadata, tagging) before transferring it to S3.  
Thanks to Rust's clear compiler error messages and robust language features, even software engineers unfamiliar with the
language can implement it easily.  
To use `UserDefinedPreprocessCallback`, you need to implement the `PreprocessCallback` trait and rebuild the s3sync
binary.  
See [UserDefinedPreprocessCallback source code](https://github.com/nidor1998/s3sync/tree/main/src/callback/user_defined_preprocess_callback.rs)
for more information.

Note: `User-defined preprocessing callback` can not modify the object's key or content itself.

### User-defined event callback

This feature is for advanced users not satisfied with the default Lua scripting.  
If you are familiar with Rust, you can use `UserDefinedEventCallback` to implement custom event handling logic, such as
logging or monitoring and custom actions before and after synchronization.  
Thanks to Rust's clear compiler error messages and robust language features, even software engineers unfamiliar with the
language can implement it easily.  
To use `UserDefinedEventCallback`, you need to implement the `EventCallback` trait and rebuild the s3sync binary.  
See [UserDefinedEventCallback source code](https://github.com/nidor1998/s3sync/tree/main/src/callback/user_defined_event_callback.rs)
for more information.

### User-defined filter callback

This feature is for advanced users not satisfied with the default Lua scripting.  
If you are familiar with Rust, you can use `UserDefinedFilterCallback` to implement custom filtering logic.  
Thanks to Rust's clear compiler error messages and robust language features, even software engineers unfamiliar with
the language can implement it easily.  
To use `UserDefinedFilterCallback`, you need to implement the `FilterCallback` trait and rebuild the s3sync binary.  
See [UserDefinedFilterCallback source code](https://github.com/nidor1998/s3sync/tree/main/src/callback/user_defined_filter_callback.rs)
for more information.

## Requirements

- x86_64 Linux (kernel 3.2 or later)
- ARM64 Linux (kernel 4.1 or later)
- x86_64 Windows 11
- ARM64 Windows 11
- macOS 11.0 or later

All features are tested on the above platforms.

## License

This project is licensed under the Apache-2.0 License.

## Installation

Download the latest binary from [GitHub Releases](https://github.com/nidor1998/s3sync/releases)

`s3sync-linux-glibc2.28` binary cannot be run on a glibc version less than or equal to 2.17. (i.e., CentOS 7, etc.)  
`s3sync-linux-musl` binary is statically linked version and can be run on any Linux distribution.  
The statically linked version is optimized for size and portability, but it may have slightly lower performance than the
glibc version.  
The glibc version is recommended if you don't have a specific requirement.

Note: The statically linked version cannot load Lua C modules.

You can also build from source following the instructions below.

### Install Rust

See [Install Rust](https://www.rust-lang.org/tools/install)

### Build

s3sync requires Rust 1.88 or later.

```bash
cargo install s3sync
```

Note: The above command ignores the project's configuration and builds with global configuration. If you want to use Lua
third-party C libraries, you need to manually download the source code and build. e.g. `cargo install --path .` .

## As a Rust library

s3sync can be used as a Rust library.   
The s3sync CLI is a very thin wrapper over the s3sync library. All CLI features are available in the library.

See [docs.rs](https://docs.rs/s3sync/latest/s3sync/) for more information.

## Usage

AWS credentials are required to use s3sync. IAM Roles, AWS CLI Profile, environment variables, etc supported.  
By default, s3sync obtains credentials from many locations (IAM Roles, environment variables, etc).  
For more information,
see [SDK authentication with AWS](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/credentials.html)

You can also specify credentials in the command line options or environment variables.

Region is required. It can be specified in the profile, environment, or command line options.

A prefix is optional. If not specified, the entire bucket will be synchronized.

If you specify a prefix, **s3sync doesn't automatically add a trailing slash.**  
For example, if you specify `s3://bucket-name/prefix` as the target, s3sync will synchronize source objects named `foo`
to `s3://bucket-name/prefixfoo`.  
And if you specify `s3://bucket-name/prefix/` as the target, s3sync will synchronize source objects named `foo` to
`s3://bucket-name/prefix/foo`.

If you use s3sync for the first time, you should use the `--dry-run` option to test the operation.

For all options, see `s3sync --help`

### Local to S3

```bash
s3sync /path/to/local s3://bucket-name/prefix
```

### S3 to Local

```bash
s3sync s3://bucket-name/prefix /path/to/local
```

### S3 to S3

```bash
s3sync s3://bucket-name1/prefix s3://bucket-name2/prefix
```

### S3 to S3 Server-side copy

Works only in the same region.

```bash
s3sync --server-side-copy s3://bucket-name1/prefix s3://bucket-name2/prefix
```

### Specify access key/secret access key

```bash
s3sync --source-access-key foo --source-secret-access-key bar s3://bucket-name/prefix /path/to/local
```

### Specify profile

```bash
s3sync --source-profile foo --target-profile bar s3://bucket-name1/prefix s3://bucket-name2/prefix
```

### Specify region

```bash
s3sync --source-profile foo --source-region ap-northeast-1 s3://bucket-name1/prefix s3://bucket-name2/prefix
```

### Versioning mode

```bash
s3sync --enable-versioning s3://bucket-name1/prefix s3://bucket-name2/prefix
```

### Custom endpoint

You can specify a S3-compatible storage endpoint.  
Warning: If you use a custom endpoint, you may need to specify `--source-force-path-style` or
`--target-force-path-style`.

```bash
s3sync --target-endpoint-url https://foo --target-force-path-style /path/to/local s3://bucket-name/prefix 
```

### Amazon S3 Transfer Acceleration

```bash
s3sync --source-accelerate --target-accelerate s3://bucket-name1/prefix s3://bucket-name2/prefix
```

### Amazon S3 Multi-Region Access Points

```bash
s3sync /path/to/local s3://arn:aws:s3::000000000000:accesspoint/xxxxxxxxxxxxx/
```

### Amazon S3 Access Points

Access Point alias is also supported.

```bash
s3sync /path/to/local s3://arn:aws:s3:000000000000:accesspoint/xxxxxxxxxxxxx/
```

### Dry run mode

```bash
s3sync --dry-run s3://bucket-name1/prefix s3://bucket-name2/prefix
```

### --delete mode

```bash
s3sync --delete s3://bucket-name1/prefix s3://bucket-name2/prefix
```

## Detailed information

### Object integrity check detail

s3sync calculates ETag(MD5) for a source object and compares them with the checksums in the target.  
Optionally, s3sync can also calculate and compare additional checksum(SHA256/SHA1/CRC32/CRC32C/CRC64NVME) for each
object.

ETag is not always MD5. If the object is uploaded with multipart upload, ETag is not MD5 digest but the MD5 digest of
these concatenated values.  
Even if multipart upload is used, s3sync can calculate and compare ETag for each part and the entire object.(with
`--auto-chunksize`)

If the object is uploaded with SSE-KMS/SSE-C/DSSE-KMS, ETag is not MD5. In this case, s3sync cannot calculate and
compare checksums for the object.

s3sync uses the following elements to verify the integrity of the object.

- `Content-MD5` header(End-to-end API level integrity check, without `--disable-content-md5` option)  
  Amazon S3 recommends using `Content-MD5` header for end-to-end integrity check.  
  Note: Amazon S3 Express One Zone storage class does not support `Content-MD5` header.

- `x-amz-content-sha256` Authentication header(without `--disable-payload-signing` option)  
  This header is SHA256 digest of the request payload.    
  Note: Some S3-compatible storage ignores this header.

- Additional checksum algorithm (Optional)  
  Amazon S3 uses this header to verify the integrity of the object and denies the request if the checksum does not
  match.   
  And s3sync can calculate and compare additional checksum algorithm that S3 returns.

  Note: As of writing this document, some S3-compatible storages do not support additional checksum algorithm.

- TLS(If not explicitly disabled)

The multipart ETag does not always match that of the source object. But with the above elements, it is almost safe to
assume that the object is not corrupted.  
With `--auto-chunksize`, s3sync can calculate and compare ETag/checksum for each part and the entire object.   
If you want strict integrity check, use `--auto-chunksize`, but it will need more API calls and time.

For more information,
see  [Checking object integrity in Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html).

#### Matrix of s3sync end-to-end object integrity check

In the case of Local to S3 or S3 to Local, s3sync compares ETags and additional checksums of Local that s3sync
calculates with those of S3.  
In the case of S3 to S3, s3sync just compares ETags and additional checksums that calculated by S3.

If an object is not verified, s3sync shows a warning message in the terminal.

Amazon S3 Express One Zone storage class does not support ETag as verification. Instead, s3sync uses additional checksum
algorithm for verification by default(CRC64NVME).

##### ETag(MD5 digest or equivalent): plain-text/SSE-S3

|                  | Local to S3   | S3 to Local                                                                                        | S3 to S3                                                                                           |
|------------------|---------------|----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|
| multipart object | always verify | verify as much as possible(without `--auto-chunksize`)<br/> always verify(with `--auto-chunksize`) | verify as much as possible(without `--auto-chunksize`)<br/> always verify(with `--auto-chunksize`) |
| single object    | always verify | always verify                                                                                      | always verify                                                                                      |

##### ETag(MD5 digest or equivalent): SSE-KMS/SSE-C/DSSE-KMS

|                  | Local to S3 | S3 to Local | S3 to S3   |
|------------------|-------------|-------------|------------|
| multipart object | not verify  | not verify  | not verify |
| single object    | not verify  | not verify  | not verify |

##### Additional checksum: plain-text/SSE-S3/SSE-KMS/SSE-C/DSSE-KMS

|                  | Local to S3   | S3 to Local   | S3 to S3                                                                                            |
|------------------|---------------|---------------|-----------------------------------------------------------------------------------------------------|
| multipart object | always verify | always verify | verify as much as possible (without `--auto-chunksize`)<br/> always verify(with `--auto-chunksize`) |
| single object    | always verify | always verify | always verify                                                                                       |

Note: To enable end-to-end additional checksum verification, `--enable-additional-checksum` must be specified.  
Note: In the case of S3 to S3, the same checksum algorithm must be used for both source and target.

### --auto-chunksize option

If `--auto-chunksize` is specified, s3sync automatically calculates the correct chunk size for multipart upload.  
This is done by `HeadObject` API with `partNumber` request parameter and `x-amz-mp-parts-count` response header.
`--auto-chunksize` requires extra API calls(one per part).  
Remember that not all S3-compatible storage supports these parameters.  
If S3-compatible storage does not support these parameters, s3sync will show a warning message in the terminal.

See: [HeadObject Reference](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html#API_HeadObject_RequestSyntax)

Note: If the chunk size for a multipart upload is unknown, verifying object integrity using ETag or composite checksum
is impossible (this applies to tools other than s3sync as well).

**Warning: In the case of S3 to S3, if the source object is uploaded with a large chunk size, s3sync will consume a lot
of
memory.**

### Retry logic detail

s3sync automatically retries with exponential backoff implemented in the AWS SDK for Rust.  
You can configure the retry behavior with `--aws-max-attempts` and `--initial-backoff-milliseconds` option.

s3sync uses another original retry logic `force retry`.  
In this logic, s3sync retries the operation that is retryable for synchronization purpose(e.g.,
`Connection reset by peer` for cases the AWS SDK for Rust does not retry even though the operation is idempotent).  
For example, if `--force-retry-count` is `5` (default) and `--aws-max-attempts` is `10` (default), s3sync retries the
operation up to total 50 times in the case of retryable error.  
If a single object fails to transfer after exceeding `--force-retry-count`, s3sync will stop the whole operation and
exit with error code `1`.

On the other hand, if an error that is not retryable occurs, s3sync will stop the whole operation immediately and exit
with error code `1`.

This behavior is useful for synchronization that is taking a long time to complete and hard to resume.  
In almost all cases, s3sync will recover from the error before the operation is stopped.

If you have a trouble with force retry(S3 SlowDown/503/429 response, etc.), you can disable it with
`--force-retry-count 0`.

If s3sync stops due to an error, you can resume the operation by running the same command again. s3sync uses incremental
transfer, so it will not transfer the same objects again.

### Filtering order

s3sync filters objects in the following order.  
You can specify multiple filters.

1. `--filter-mtime-before`
2. `--filter-mtime-after`
3. `--filter-smaller-size`
4. `--filter-larger-size`
5. `--filter-include-regex`
6. `--filter-exclude-regex`
7. `FilterCallback(--filter-callback-lua-script/UserDefinedFilterCallback)`
8. `Update check(Check the source object has been modified)`
9. `--filter-include-content-type-regex`
10. `--filter-exclude-content-type-regex`
11. `--filter-include-metadata-regex`
12. `--filter-exclude-metadata-regex`
13. `--filter-include-tag-regex`
14. `--filter-exclude-tag-regex`
15. `PreprocessCallback(--preprocess-callback-lua-script/UserDefinedPreprocessCallback)`

It is recommended to filter before `Update check`, because after that, s3sync needs to call extra API calls.  
But after `Update check`, you can get more information about the object, such as the additional checksum, user-defined
metadata, tagging, etc.

Note: `PreprocessCallback(--preprocess-callback-lua-script/UserDefinedPreprocessCallback)` is called just before
transferring the object to S3. So dry-run does not call this callback.

### Incremental transfer detail

s3sync transfers only modified objects. It checks the `LastModified` timestamp.

If `--check-size` is specified, s3sync only checks the size of the object.

At first, incremental transfer lists all objects in the target.  
Then, s3sync compares the objects and transfers only modified objects.

Therefore, incremental transfer takes time to start for large numbers of existing target objects.  
In my environment, Amazon S3 takes about 1 second per 50,000 objects to list objects in the target. (It depends on
remote
storage.)

If there are few objects in the target, incremental transfer starts immediately, regardless of the number of source
objects.

### Versioning support detail

s3sync uses user-defined metadata to check the version of the object.  
If `--enable-versioning` is specified, s3sync adds user-defined metadata to the object.
If you transfer to an existing bucket, because of the lack of user-defined metadata, s3sync will transfer all versions
of
the object.  
Generally, you should use `--enable-versioning` when you transfer to a new bucket.

With `--filter-mtime-before` and `--filter-mtime-after` options, you can get snapshots of the objects at a specific
period.

Intermediate delete markers are not synchronized. Latest version delete markers are synchronized.

user-defined metadata: `s3sync_origin_version_id`, `s3sync_origin_last_modified`

### Versioning and point-in-time snapshot

s3sync supports point-in-time recovery of objects.

You can use `--point-in-time` option to enable point-in-time synchronization.

For example, if you want to synchronize objects at `2025-07-16T06:37:59Z`, you can use the following command:

S3 to S3(In the same region):

```bash
s3sync --server-side-copy --point-in-time 2025-07-16T06:37:59Z s3://source_bucket s3://target_bucket
```

S3 to Local:

```bash
s3sync --point-in-time 2025-07-16T06:37:59Z s3://source_bucket /path/to/local
```

### Metadata support detail

The following metadata of the S3 object is synchronized.

- Content-Type
- Content-Encoding
- Cache-Control
- Content-Disposition
- Content-Language
- Expires
- User-defined metadata

### Website redirect location

If the source object has `x-amz-website-redirect-location` metadata, s3sync copies it to the target object.

And, you can specify `--website-redirect-location` option to set the redirect location for the target object.

### Memory usage detail

s3sync consumes memory for each worker.   
For single-object uploads, approximately `average size of the object * worker-size(default 16) * 2`.  
For multipart uploads, approximately
`multipart chunksize(default 8MiB) * worker-size(default 16) * 2 + multipart chunksize(default 8MiB) * max-parallel-uploads(default 16)`.

Because s3sync uses incremental transfer, it lists all objects in the target bucket and stores the result in memory.  
Therefore, if there are a large number of objects in the target bucket, s3sync can consume a lot of memory.  
If you do not use the `--delete` option, s3sync will consume about 100MB per 1,000,000 target objects.  
If you use the `--delete` option, s3sync will consume about 250MB per 1,000,000 target objects.

To reduce memory usage, you can divide the target objects by prefix and run s3sync multiple times or specify
`--remove-modified-filter` and `--head-each-target` options.  
You can also divide the target objects by filter and run s3sync multiple times.

The `--head-each-target` option calls the `HeadObject` API for each source object, but it is a trade-off between memory
usage and API calls.

### Parallel object listing

By default, s3sync lists objects in the source and target in parallel (default 16 workers).  
The parallel listing is enabled up to the second level of subdirectories or prefixes.  
The depth is configurable with `--max-parallel-listing-max-depth` option.

For example, if the source is `s3://bucket-name/prefix` and there are many objects under `prefix/dir1`,
`prefix/dir2`, ..., `prefix/dir16`, s3sync lists objects under these prefixes in parallel.

You can configure the number of parallel listing workers with `--max-parallel-listings` option.  
If set to `1`, parallel listing is disabled.

This feature can significantly improve performance with incremental transfer when there are many objects in the source
and target.

With express one zone storage class, parallel listing may return in progress multipart upload objects.   
So, parallel listing is disabled by default when the source or target bucket uses express one zone storage class.   
You can enable it with `--allow-parallel-listings-in-express-one-zone` option.

When `--enable-versioning` or `--point-in-time` option is specified, parallel listing is disabled.

Note: Parallel listing may use CPU and memory.

### --max-parallel-listing-max-depth option

By default, s3sync lists objects in the source and target in parallel up to the second level of
subdirectories or prefixes.  
And deeper levels are listed without parallelization.
This is because parallel listing at deeper levels may not improve incremental transfer performance.

But in some cases, parallel listing at deeper levels may improve incremental transfer performance.
You can configure the maximum depth of parallel listing workers with `--max-parallel-listing-max-depth` option.

### S3 Permissions

s3sync requires the following permissions.

#### Source bucket

```
"Action": [
    "s3:GetBucketVersioning",
    "s3:GetObject",
    "s3:GetObjectAttributes",
    "s3:GetObjectTagging",
    "s3:GetObjectVersion",
    "s3:GetObjectVersionAttributes",
    "s3:GetObjectVersionTagging",
    "s3:ListBucket",
    "s3:ListBucketVersions",
    "s3express:CreateSession",
]
```

#### Target bucket

```
"Action": [
    "s3:AbortMultipartUpload",
    "s3:DeleteObject",
    "s3:DeleteObjectTagging",
    "s3:GetBucketVersioning",
    "s3:GetObject",
    "s3:GetObjectTagging",
    "s3:GetObjectVersion",
    "s3:ListBucket",
    "s3:ListBucketVersions",
    "s3:PutObject",
    "s3:PutObjectTagging",
    "s3express:CreateSession"
]
```

### Lua VM

Each type of callback has its own Lua VM and memory limit.  
Lua VM is shared between workers and called serially.  
Each type of Lua script is loaded and compiled once at the CLI argument parsing stage and lives until the end of the
total synchronization operations.

### Lua VM security

By default, a Lua script runs in a safe mode.
Lua's [Operating System facilities](https://www.lua.org/manual/5.4/manual.html#6.9)
and [Input and Output Facilities](https://www.lua.org/manual/5.4/manual.html#6.8) are disabled by default.  
This is because these facilities can be used to execute arbitrary commands, which can be a security risk. (especially
set-uid/set-gid/fs-capability programs)  
Also, Lua VM is not allowed to load unsafe standard libraries or C modules.

If these restrictions are too strict, you can use `--allow-lua-os-library` or `--allow-lua-unsafe-vm` options to allow
Lua's OS facilities and unsafe standard libraries or C modules.

Note: The statically linked binary cannot load C modules.

### Lua script error

Generally, if a Lua script raises an error, s3sync will stop the operation and exit with error code `1`.  
But an event callback Lua script does not stop the operation, just shows the warning message.

### Lua version

s3sync uses [mlua](https://docs.rs/mlua/latest/mlua/) for Lua scripting support. By default, s3sync uses Lua 5.4.  
If you want to use `LuaJIT`, `luau-jit`, etc, you can modify the `Cargo.toml` file and set the `mlua` feature.  
For more information, see [mlua feature flags](https://github.com/mlua-rs/mlua#feature-flags).

### CLI process exit codes

- 0: Exit without error
- 1: Exit with error
- 2: Invalid arguments
- 3: Exit with warning
- 101: Abnormal termination (Rust panic, it's a bug of s3sync)

## Advanced options

### --worker-size

The number of workers. Many workers can improve performance. But it also increases CPU and memory usage.  
Default: 16

If you specify many workers, you may need to increase the number of open files.  
For example, on Linux: `ulimit -n 8192`

### --max-parallel-uploads

The maximum number of parallel uploads/downloads for objects larger than `multipart-threshold`.  
This feature is implemented by using HTTP `Range` header.  
Default: 16

**Note: Specifying a large number of parallel uploads(64 or more) is not recommended. It can cause OS to be unstable.**

### --force-retry-count

s3sync forcibly retries the operation that AWS SDK for Rust cannot retry.  
For example, in the case of `connection reset by peer`, s3sync will retry the operation.

### --remove-modified-filter

If you want to overwrite the existing objects, specify the option.

### --filter-include-regex/--filter-exclude-regex

You can specify the regular expression to filter the source objects.  
The regular expression syntax is the same as [fancy_regex](https://docs.rs/fancy-regex/latest/fancy_regex/#syntax).

### --check-etag

For incremental transfer, s3sync compares the ETag of the source object with the ETag of the target object. If the ETag
is different, s3sync transfers the object.

with `--auto-chunksize`, s3sync can calculate and compare ETag for each part and the entire object. It is useful if you
don't know the correct chunk size. But it will need more API calls and time.

If both sides are S3, s3sync only compares the ETag of the source object with the ETag of the target object. If either
side is not S3, s3sync calculates ETag of the local object.

You will need to know about Amazon S3 ETag.  
See: [API Reference](https://docs.aws.amazon.com/AmazonS3/latest/API/API_Object.html)

### --put-last-modified-metadata

This option adds user-defined metadata that contains the last-modified time of the source object.

user-defined metadata: `s3sync_origin_last_modified`

### --additional-checksum-algorithm

If you want to use additional checksum for upload, specify the algorithm.

Calculating an additional checksum is costly with large local objects.  
SHA256/SHA1 additional checksum, in particular, may require significant processing time.

### --enable-additional-checksum

If you want to use additional checksums for download, specify the option.

Calculating an additional checksum is costly with large local objects.  
SHA256/SHA1 additional checksum, in particular, may require significant processing time.

Warning: Even if the object was uploaded with additional checksum, without this option, s3sync does not verify
additional checksum.

### --disable-multipart-verify

When an object is uploaded with multipart upload, its ETag may not match that of the target object.  
This can occur when the chunk size that the object was uploaded with is different. If you don't know the correct chunk
size, you can disable the verification with this option.  
You can specify the chunk size with `--multipart-threshold` and `--multipart-chunksize` (Default: 8MiB).

If extra API calls are allowed, you can use `--auto-chunksize` instead.  
However, please note that not all S3-compatible storage supports this option.   
**Warning: In the case of S3 to S3, if the source object is uploaded with a large chunk size, s3sync will consume a lot
of
memory.**

### --disable-additional-checksum-verify

When `--additional-checksum-algorithm` is specified, s3sync verifies the additional checksum of the target object.  
But if source S3-compatible storage does not support additional checksum, s3sync cannot verify the additional
checksum.  
In this case, you can disable the verification with this option, while keeping the additional checksum in the target
object.

### -v

s3sync uses [tracing-subscriber](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/) for tracing.    
More occurrences increase the verbosity.  
For example, `-v`: show `info`, `-vv`: show `debug`, `-vvv`: show `trace`  
By default, s3sync shows warning and error messages.

`info` and `debug` messages are useful for troubleshooting. `trace` messages are useful for debugging.

Instead of `-v`, you can use `RUST_LOG` environment variable.

On the other hand, you can use `-q`, `-qq` to reduce the verbosity.

### --aws-sdk-tracing

For troubleshooting, s3sync can output the AWS SDK for Rust's tracing information.  
Instead of `--aws-sdk-tracing`, you can use `RUST_LOG` environment variable.

### --auto-complete-shell

You can output the shell script to complete the command.

```bash
s3sync --auto-complete-shell bash
```

### -h/--help

For more information, see `s3sync -h`.

## All command line options

<details>
<summary>Click to expand to view all command line options </summary>

```bash
$ s3sync -h
Usage: s3sync [OPTIONS] [SOURCE] [TARGET]

Arguments:
  [SOURCE]  s3://<BUCKET_NAME>[/prefix] or local path [env: SOURCE=]
  [TARGET]  s3://<BUCKET_NAME>[/prefix] or local path [env: TARGET=]

Options:
  -v, --verbose...  Increase logging verbosity
  -q, --quiet...    Decrease logging verbosity
  -h, --help        Print help (see more with '--help')
  -V, --version     Print version

General:
      --dry-run           A simulation mode. No actions will be performed [env: DRY_RUN=]
      --show-no-progress  Don't show the progress bar [env: SHOW_NO_PROGRESS=]
      --server-side-copy  Use server-side copy. This option is only available both source and target are S3 storage.
                          It cannot work with between different object storages or regions. [env: SERVER_SIDE_COPY=]

AWS Configuration:
      --aws-config-file <FILE>
          Location of the file that the AWS CLI uses to store configuration profiles [env: AWS_CONFIG_FILE=]
      --aws-shared-credentials-file <FILE>
          Location of the file that the AWS CLI uses to store access keys [env: AWS_SHARED_CREDENTIALS_FILE=]
      --source-profile <SOURCE_PROFILE>
          Source AWS CLI profile [env: SOURCE_PROFILE=]
      --source-access-key <SOURCE_ACCESS_KEY>
          Source access key [env: SOURCE_ACCESS_KEY=]
      --source-secret-access-key <SOURCE_SECRET_ACCESS_KEY>
          Source secret access key [env: SOURCE_SECRET_ACCESS_KEY=]
      --source-session-token <SOURCE_SESSION_TOKEN>
          Source session token [env: SOURCE_SESSION_TOKEN=]
      --target-profile <TARGET_PROFILE>
          Target AWS CLI profile [env: TARGET_PROFILE=]
      --target-access-key <TARGET_ACCESS_KEY>
          Target access key [env: TARGET_ACCESS_KEY=]
      --target-secret-access-key <TARGET_SECRET_ACCESS_KEY>
          Target secret access key [env: TARGET_SECRET_ACCESS_KEY=]
      --target-session-token <TARGET_SESSION_TOKEN>
          Target session token [env: TARGET_SESSION_TOKEN=]

Source Options:
      --source-region <SOURCE_REGION>
          Source region [env: SOURCE_REGION=]
      --source-endpoint-url <SOURCE_ENDPOINT_URL>
          Source endpoint url [env: SOURCE_ENDPOINT_URL=]
      --source-accelerate
          Use Amazon S3 Transfer Acceleration for the source bucket [env: SOURCE_ACCELERATE=]
      --source-request-payer
          Use request payer for the source bucket [env: SOURCE_REQUEST_PAYER=]
      --source-force-path-style
          Force path-style addressing for source endpoint [env: SOURCE_FORCE_PATH_STYLE=]

Target Options:
      --target-region <TARGET_REGION>
          Target region [env: TARGET_REGION=]
      --target-endpoint-url <TARGET_ENDPOINT_URL>
          Target endpoint url [env: TARGET_ENDPOINT_URL=]
      --target-accelerate
          Use Amazon S3 Transfer Acceleration for the target bucket [env: TARGET_ACCELERATE=]
      --target-request-payer
          Use request payer for the target bucket [env: TARGET_REQUEST_PAYER=]
      --target-force-path-style
          Force path-style addressing for target endpoint [env: TARGET_FORCE_PATH_STYLE=]
      --storage-class <STORAGE_CLASS>
          Type of storage to use for the target object.
          Valid choices: STANDARD | REDUCED_REDUNDANCY | STANDARD_IA | ONE-ZONE_IA | INTELLIGENT_TIERING | GLACIER |
                         DEEP_ARCHIVE | GLACIER_IR | EXPRESS_ONEZONE [env: STORAGE_CLASS=]

Filtering:
      --filter-mtime-before <FILTER_MTIME_BEFORE>
          Sync only objects older than given time (RFC3339 datetime).
          Example: 2023-02-19T12:00:00Z [env: FILTER_MTIME_BEFORE=]
      --filter-mtime-after <FILTER_MTIME_AFTER>
          Sync only objects newer than OR EQUAL TO given time (RFC3339 datetime).
          Example: 2023-02-19T12:00:00Z [env: FILTER_MTIME_AFTER=]
      --filter-smaller-size <FILTER_SMALLER_SIZE>
          Sync only objects smaller than given size.
          Allow suffixes: KB, KiB, MB, MiB, GB, GiB, TB, TiB [env: FILTER_SMALLER_SIZE=]
      --filter-larger-size <FILTER_LARGER_SIZE>
          Sync only objects larger than OR EQUAL TO given size.
          Allow suffixes: KB, KiB, MB, MiB, GB, GiB, TB, TiB [env: FILTER_LARGER_SIZE=]
      --filter-include-regex <FILTER_INCLUDE_REGEX>
          Sync only objects that match a given regular expression [env: FILTER_INCLUDE_REGEX=]
      --filter-exclude-regex <FILTER_EXCLUDE_REGEX>
          Do not sync objects that match a given regular expression [env: FILTER_EXCLUDE_REGEX=]
      --filter-include-content-type-regex <FILTER_INCLUDE_CONTENT_TYPE_REGEX>
          Sync only objects that have Content-Type matching a given regular expression.
          If the source is local storage, Content-Type is guessed by the file extension,
          Unless --no-guess-mime-type is specified.
          It may take an extra API call to get Content-Type of the object.
           [env: FILTER_INCLUDE_CONTENT_TYPE_REGEX=]
      --filter-exclude-content-type-regex <FILTER_EXCLUDE_CONTENT_TYPE_REGEX>
          Do not sync objects that have Content-Type matching a given regular expression.
          If the source is local storage, Content-Type is guessed by the file extension,
          Unless --no-guess-mime-type is specified.
          It may take an extra API call to get Content-Type of the object.
           [env: FILTER_EXCLUDE_CONTENT_TYPE_REGEX=]
      --filter-include-metadata-regex <FILTER_INCLUDE_METADATA_REGEX>
          Sync only objects that have metadata matching a given regular expression.
          Keys(lowercase) must be sorted in alphabetical order, and comma separated.
          This filter is applied after all other filters(except tag filters).
          It may take an extra API call to get metadata of the object.

          Example: "key1=(value1|value2),key2=value2" [env: FILTER_INCLUDE_METADATA_REGEX=]
      --filter-exclude-metadata-regex <FILTER_EXCLUDE_METADATA_REGEX>
          Do not sync objects that have metadata matching a given regular expression.
          Keys(lowercase) must be sorted in alphabetical order, and comma separated.
          This filter is applied after all other filters(except tag filters).
          It may take an extra API call to get metadata of the object.

          Example: "key1=(value1|value2),key2=value2" [env: FILTER_EXCLUDE_METADATA_REGEX=]
      --filter-include-tag-regex <FILTER_INCLUDE_TAG_REGEX>
          Sync only objects that have tag matching a given regular expression.
          Keys must be sorted in alphabetical order, and '&' separated.
          This filter is applied after all other filters.
          It takes an extra API call to get tags of the object.

          Example: "key1=(value1|value2)&key2=value2" [env: FILTER_INCLUDE_TAG_REGEX=]
      --filter-exclude-tag-regex <FILTER_EXCLUDE_TAG_REGEX>
          Do not sync objects that have tag matching a given regular expression.
          Keys must be sorted in alphabetical order, and '&' separated.
          This filter is applied after all other filters.
          It takes an extra API call to get tags of the object.

          Example: "key1=(value1|value2)&key2=value2" [env: FILTER_EXCLUDE_TAG_REGEX=]

Update Checking:
      --remove-modified-filter
          Do not update checking(ListObjectsV2) for modification in the target storage [env: REMOVE_MODIFIED_FILTER=]
      --check-size
          Use object size for update checking [env: CHECK_SIZE=]
      --check-etag
          Use ETag for update checking [env: CHECK_ETAG=]
      --check-mtime-and-etag
          Use the modification time and ETag for update checking.
          If the source modification date is newer, check the ETag.
           [env: CHECK_MTIME_AND_ETAG=]
      --check-additional-checksum <CHECK_ADDITIONAL_CHECKSUM>
          Use additional checksum for update checking [env: CHECK_ADDITIONAL_CHECKSUM=]
      --check-mtime-and-additional-checksum <CHECK_MTIME_AND_ADDITIONAL_CHECKSUM>
          Use the modification time and additional checksum for update checking.
          If the source modification date is newer, check the additional checksum.
           [env: CHECK_MTIME_AND_ADDITIONAL_CHECKSUM=]

Verification:
      --additional-checksum-algorithm <ADDITIONAL_CHECKSUM_ALGORITHM>
          Additional checksum algorithm for upload [env: ADDITIONAL_CHECKSUM_ALGORITHM=]
      --full-object-checksum
          Use full object checksum for verification. CRC64NVME automatically use full object checksum.
          This option cannot be used with SHA1/SHA256 additional checksum. [env: FULL_OBJECT_CHECKSUM=]
      --enable-additional-checksum
          Enable additional checksum for download [env: ENABLE_ADDITIONAL_CHECKSUM=]
      --disable-multipart-verify
          Disable multipart upload verification with ETag/additional checksum [env: DISABLE_MULTIPART_VERIFY=]
      --disable-etag-verify
          Disable ETag verification [env: DISABLE_ETAG_VERIFY=]
      --disable-additional-checksum-verify
          Disable additional checksum verification
          But use additional checksum for upload (The hash value is stored in the target object). [env: DISABLE_ADDITIONAL_CHECKSUM_VERIFY=]

Performance:
      --worker-size <WORKER_SIZE>
          Number of workers for synchronization [env: WORKER_SIZE=] [default: 16]
      --max-parallel-uploads <MAX_PARALLEL_UPLOADS>
          Maximum number of parallel multipart uploads/downloads [env: MAX_PARALLEL_UPLOADS=] [default: 16]
      --max-parallel-listings <MAX_PARALLEL_LISTINGS>
          Maximum number of parallel listings of objects. [env: MAX_PARALLEL_LISTINGS=] [default: 16]
      --max-parallel-listing-max-depth <MAX_PARALLEL_LISTING_MAX_DEPTH>
          Maximum depth(sub directroy/prefix) of parallel listings. [env: MAX_PARALLEL_LISTING_MAX_DEPTH=] [default: 2]
      --object-listing-queue-size <OBJECT_LISTING_QUEUE_SIZE>
          Queue size for object listings [env: OBJECT_LISTING_QUEUE_SIZE=] [default: 200000]
      --allow-parallel-listings-in-express-one-zone
          Allow parallel listings in express one zone storage class.
          It may include multipart upload in progress objects in the listing result. [env: ALLOW_PARALLEL_LISTINGS_IN_EXPRESS_ONE_ZONE=]
      --rate-limit-objects <RATE_LIMIT_OBJECTS>
          Rate limit objects per second [env: RATE_LIMIT_OBJECTS=]
      --rate-limit-bandwidth <RATE_LIMIT_BANDWIDTH>
          Rate limit bandwidth(bytes per sec). Allow suffixes: MB, MiB, GB, GiB [env: RATE_LIMIT_BANDWIDTH=]

Multipart Settings:
      --multipart-threshold <MULTIPART_THRESHOLD>
          Object size threshold that s3sync uses for multipart upload
          Allow suffixes: MB, MiB, GB, GiB.
          The larger the size, the larger the memory usage. [env: MULTIPART_THRESHOLD=] [default: 8MiB]
      --multipart-chunksize <MULTIPART_CHUNKSIZE>
          Chunk size that s3sync uses for multipart upload of individual files
          Allow suffixes: MB, MiB, GB, GiB.
          The larger the size, the larger the memory usage. [env: MULTIPART_CHUNKSIZE=] [default: 8MiB]
      --auto-chunksize
          Automatically adjusts a chunk size to match the source or target.
          It takes extra HEAD requests(1 API call per part). [env: AUTO_CHUNKSIZE=]

Metadata/Headers:
      --cache-control <CACHE_CONTROL>
          Cache-Control HTTP header to set on the target object [env: CACHE_CONTROL=]
      --content-disposition <CONTENT_DISPOSITION>
          Content-Disposition HTTP header to set on the target object [env: CONTENT_DISPOSITION=]
      --content-encoding <CONTENT_ENCODING>
          Content-Encoding HTTP header to set on the target object [env: CONTENT_ENCODING=]
      --content-language <CONTENT_LANGUAGE>
          Content-Language HTTP header to set on the target object [env: CONTENT_LANGUAGE=]
      --content-type <CONTENT_TYPE>
          Content-Type HTTP header to set on the target object [env: CONTENT_TYPE=]
      --expires <EXPIRES>
          Expires HTTP header to set on the target object(RFC3339 datetime)
          Example: 2023-02-19T12:00:00Z [env: EXPIRES=]
      --metadata <METADATA>
          Metadata to set on the target object
          Example: key1=value1,key2=value2 [env: METADATA=]
      --website-redirect <WEBSITE_REDIRECT>
          x-amz-website-redirect-location header to set on the target object [env: WEBSITE_REDIRECT=]
      --no-sync-system-metadata
          Do not sync system metadata
          System metadata: content-disposition, content-encoding, content-language, content-type,
                           cache-control, expires, website-redirect [env: NO_SYNC_SYSTEM_METADATA=]
      --no-sync-user-defined-metadata
          Do not sync user-defined metadata [env: NO_SYNC_USER_DEFINED_METADATA=]

Tagging:
      --tagging <TAGGING>    Tagging to set on the target object.
                             Key/value must be encoded as UTF-8 then URLEncoded URL query parameters without tag name duplicates.

                             Example: key1=value1&key2=value2 [env: TAGGING=]
      --disable-tagging      Do not copy tagging [env: DISABLE_TAGGING=]
      --sync-latest-tagging  Copy the latest tagging from the source if necessary.
                             If this option is enabled, the --remove-modified-filter and
                             --head-each-target options are automatically enabled. [env: SYNC_LATEST_TAGGING=]

Versioning:
      --enable-versioning              Sync all version objects in the source storage to the target versioning storage.
                                         [env: ENABLE_VERSIONING=]
      --point-in-time <POINT_IN_TIME>  Sync only objects at a specific point in time (RFC3339 datetime).
                                       The source storage must be a versioning enabled S3 bucket.
                                       By default, the target storage's objects will always be overwritten with the source's objects.

                                       Example: 2025-07-16T12:00:00Z [env: POINT_IN_TIME=]

Encryption:
      --sse <SSE>
          Server-side encryption. Valid choices: AES256 | aws:kms | aws:kms:dsse [env: SSE=]
      --sse-kms-key-id <SSE_KMS_KEY_ID>
          SSE KMS ID key [env: SSE_KMS_KEY_ID=]
      --source-sse-c <SOURCE_SSE_C>
          Source SSE-C algorithm. Valid choices: AES256 [env: SOURCE_SSE_C=]
      --source-sse-c-key <SOURCE_SSE_C_KEY>
          Source SSE-C customer-provided encryption key(256bit key. must be base64 encoded) [env: SOURCE_SSE_C_KEY=]
      --source-sse-c-key-md5 <SOURCE_SSE_C_KEY_MD5>
          Source base64 encoded MD5 digest of source_sse_c_key [env: SOURCE_SSE_C_KEY_MD5=]
      --target-sse-c <TARGET_SSE_C>
          Target SSE-C algorithm. Valid choices: AES256 [env: TARGET_SSE_C=]
      --target-sse-c-key <TARGET_SSE_C_KEY>
          Target SSE-C customer-provided encryption key(256bit key. must be base64 encoded) [env: TARGET_SSE_C_KEY=]
      --target-sse-c-key-md5 <TARGET_SSE_C_KEY_MD5>
          Target base64 encoded MD5 digest of target-sse-c-key [env: TARGET_SSE_C_KEY_MD5=]

Reporting:
      --report-sync-status           Report sync status to the target storage.
                                     Default verification is for ETag. For additional checksum, use --check-additional-checksum.
                                     For more precise control, use with --auto-chunksize. [env: REPORT_SYNC_STATUS=]
      --report-metadata-sync-status  Report metadata sync status to the target storage.
                                     It must be used with --report-sync-status.
                                     Note: s3sync generated user-defined metadata(s3sync_origin_version_id/s3sync_origin_last_modified) were ignored.
                                           Because they are usually different from the source storage. [env: REPORT_METADATA_SYNC_STATUS=]
      --report-tagging-sync-status   Report tagging sync status to the target storage.
                                     It must be used with --report-sync-status. [env: REPORT_TAGGING_SYNC_STATUS=]

Tracing/Logging:
      --json-tracing           Show trace as json format [env: JSON_TRACING=]
      --aws-sdk-tracing        Enable aws sdk tracing [env: AWS_SDK_TRACING=]
      --span-events-tracing    Show span event tracing [env: SPAN_EVENTS_TRACING=]
      --disable-color-tracing  Disable ANSI terminal colors [env: DISABLE_COLOR_TRACING=]

Retry Options:
      --aws-max-attempts <max_attempts>
          Maximum retry attempts that s3sync retry handler use [env: AWS_MAX_ATTEMPTS=] [default: 10]
      --initial-backoff-milliseconds <initial_backoff>
          A multiplier value used when calculating backoff times as part of an exponential backoff with jitter strategy.
           [env: INITIAL_BACKOFF_MILLISECONDS=] [default: 100]
      --force-retry-count <FORCE_RETRY_COUNT>
          Maximum force retry attempts that s3sync retry handler use [env: FORCE_RETRY_COUNT=] [default: 5]
      --force-retry-interval-milliseconds <force_retry_interval>
          Sleep interval (milliseconds) between s3sync force retries on error.
           [env: FORCE_RETRY_INTERVAL_MILLISECONDS=] [default: 1000]

Timeout Options:
      --operation-timeout-milliseconds <operation_timeout>
          Operation timeout (milliseconds). For details, see the AWS SDK for Rust TimeoutConfig documentation.
          The default has no timeout. [env: OPERATION_TIMEOUT_MILLISECONDS=]
      --operation-attempt-timeout-milliseconds <operation_attempt_timeout>
          Operation attempt timeout (milliseconds). For details, see the AWS SDK for Rust TimeoutConfig documentation.
          The default has no timeout. [env: OPERATION_ATTEMPT_TIMEOUT_MILLISECONDS=]
      --connect-timeout-milliseconds <connect_timeout>
          Connect timeout (milliseconds).The default has AWS SDK default timeout (Currently 3100 milliseconds).
           [env: CONNECT_TIMEOUT_MILLISECONDS=]
      --read-timeout-milliseconds <read_timeout>
          Read timeout (milliseconds). The default has no timeout. [env: READ_TIMEOUT_MILLISECONDS=]

Advanced:
      --warn-as-error
          Treat warnings as errors(except for the case of ETag/checksum mismatch, etc.) [env: WARN_AS_ERROR=]
      --ignore-symlinks
          Ignore symbolic links [env: IGNORE_SYMLINKS=]
      --head-each-target
          HeadObject is used to check whether an object has been modified in the target storage.
          It reduces the possibility of race condition issue [env: HEAD_EACH_TARGET=]
      --acl <ACL>
          ACL for the objects
          Valid choices: private | public-read | public-read-write | authenticated-read | aws-exec-read |
                         bucket-owner-read | bucket-owner-full-control [env: ACL=]
      --no-guess-mime-type
          Do not try to guess the mime type of local file [env: NO_GUESS_MIME_TYPE=]
      --max-keys <MAX_KEYS>
          Maximum number of objects returned in a single list object request [env: MAX_KEYS=] [default: 1000]
      --put-last-modified-metadata
          Put last modified of the source to metadata [env: PUT_LAST_MODIFIED_METADATA=]
      --auto-complete-shell <SHELL>
          Generate a auto completions script.
          Valid choices: bash, fish, zsh, powershell, elvish. [env: AUTO_COMPLETE_SHELL=]
      --disable-stalled-stream-protection
          Disable stalled stream protection [env: DISABLE_STALLED_STREAM_PROTECTION=]
      --disable-payload-signing
          Disable payload signing for object uploads [env: DISABLE_PAYLOAD_SIGNING=]
      --disable-content-md5-header
          Disable Content-MD5 header for object uploads. It disables the ETag verification for the uploaded object.
           [env: DISABLE_CONTENT_MD5_HEADER=]
      --disable-express-one-zone-additional-checksum
          Disable default additional checksum verification in Express One Zone storage class.
            [env: DISABLE_EXPRESS_ONE_ZONE_ADDITIONAL_CHECKSUM=]
      --delete-excluded
          When used in combination with --delete options, supplied --filter-exclude-regex patterns will not prevent an object from being deleted.
           [env: DELETE_EXCLUDED=]
      --if-match
          Add an If-Match header for PutObject/CompleteMultipartUpload/DeleteObject requests.
          This is for like an optimistic lock. [env: IF_MATCH=]
      --copy-source-if-match
          Add an x-amz-copy-source-if-match header for CopyObject/UploadPartCopy requests.
          This is for like an optimistic lock. [env: COPY_SOURCE_IF_MATCH=]
      --if-none-match
          Uploads the object only if the object key name does not already exist in the specified bucket.
          This is for like an optimistic lock. [env: IF_NONE_MATCH=]
      --max-delete <MAX_DELETE>
          Don't delete more than a specified number of objects [env: MAX_DELETE=]
      --ignore-glacier-warnings
          Suppress warnings related to Amazon S3 Glacier storage class objects during GetObject requests [env: IGNORE_GLACIER_WARNINGS=]

Lua scripting support:
      --preprocess-callback-lua-script <PREPROCESS_CALLBACK_LUA_SCRIPT>
          Path to the Lua script that is executed as preprocess callback [env: PREPROCESS_CALLBACK_LUA_SCRIPT=]
      --event-callback-lua-script <EVENT_CALLBACK_LUA_SCRIPT>
          Path to the Lua script that is executed as event callback [env: EVENT_CALLBACK_LUA_SCRIPT=]
      --filter-callback-lua-script <FILTER_CALLBACK_LUA_SCRIPT>
          Path to the Lua script that is executed as filter callback [env: FILTER_CALLBACK_LUA_SCRIPT=]
      --allow-lua-os-library
          Allow Lua OS and I/O library functions in the Lua script. [env: ALLOW_LUA_OS_LIBRARY=]
      --lua-vm-memory-limit <LUA_VM_MEMORY_LIMIT>
          Memory limit for the Lua VM. Allow suffixes: KB, KiB, MB, MiB, GB, GiB.
          Zero means no limit.
          If the memory limit is exceeded, the whole process will be terminated. [env: LUA_VM_MEMORY_LIMIT=] [default: 64MiB]

Dangerous:
      --allow-lua-unsafe-vm  Allow unsafe Lua VM functions in the Lua script.
                             It allows the Lua script to load unsafe standard libraries or C modules. [env: ALLOW_LUA_UNSAFE_VM=]
      --delete               Delete objects that exist in the target but not in the source.
                             Exclude filters other than --filter-exclude-regex will not prevent an object from being deleted.
                             [Warning] Since this can cause data loss, test first with the --dry-run option.
                               [env: DELETE=]
$
```

</details>

## About testing

**Supported target: Amazon S3 only.**

Support for S3-compatible storage is on a best-effort basis and may behave differently.   
s3sync has been tested with Amazon S3. s3sync has many e2e tests and unit tests and runs every time when a new version
is released.  
S3-compatible storage is not tested when a new version is released (I test only when making major changes).  
This is because S3-compatible storage may have different behaviors and features.  
Since there is no official certification for S3-compatible storage, comprehensive testing is not possible.

## Contributing

While this project began as a personal hobby, it has been built with careful attention to production-quality standards.

- Suggestions and bug reports are welcome, but responses are not guaranteed.
- Pull requests for new features are generally not accepted, as they may conflict with the design philosophy.
- If you find this project useful, feel free to fork and modify it as you wish.

🔒 I consider this project to be “complete” and will maintain it only minimally going forward.  
However, I intend to keep the AWS SDK for Rust and other dependencies up to date monthly.