S3 Compatible Cloud Storage client for JavaScript/TypeScript
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
This document covers all bucket-related operations including creation, deletion, listing, and advanced bucket management features like policies, versioning, lifecycle, encryption, and replication.
// Basic bucket creation
await client.makeBucket(bucketName, region?, makeOpts?)
// Parameters
bucketName: string // Bucket name (must follow S3 naming rules)
region?: string // AWS region (default: 'us-east-1')
makeOpts?: MakeBucketOpt // Additional optionsinterface MakeBucketOpt {
ObjectLocking?: boolean // Enable object locking (cannot be changed later)
}// Simple bucket creation
await client.makeBucket('my-bucket')
// Bucket with specific region
await client.makeBucket('my-bucket', 'us-west-2')
// Bucket with object locking enabled
await client.makeBucket('locked-bucket', 'us-east-1', {
ObjectLocking: true
})const exists = await client.bucketExists(bucketName)
// Returns: Promise<boolean>const bucketName = 'my-bucket'
if (await client.bucketExists(bucketName)) {
console.log('Bucket exists')
} else {
console.log('Bucket does not exist')
await client.makeBucket(bucketName)
}const buckets = await client.listBuckets()
// Returns: Promise<BucketItemFromList[]>interface BucketItemFromList {
name: string // Bucket name
creationDate: Date // Creation timestamp
}const buckets = await client.listBuckets()
buckets.forEach(bucket => {
console.log(`Bucket: ${bucket.name}, Created: ${bucket.creationDate}`)
})await client.removeBucket(bucketName)
// Note: Bucket must be empty before deletiontry {
await client.removeBucket('my-bucket')
console.log('Bucket deleted successfully')
} catch (error) {
if (error.code === 'BucketNotEmpty') {
console.log('Bucket is not empty, delete all objects first')
// Delete all objects, then retry bucket deletion
}
}Lists all incomplete multipart uploads in a bucket.
const stream = client.listIncompleteUploads(bucketName, prefix?, recursive?)
// Parameters
bucketName: string // Bucket name
prefix?: string // Filter by object name prefix (default: '')
recursive?: boolean // List recursively (default: false)
// Returns: BucketStream<IncompleteUploadedBucketItem>interface IncompleteUploadedBucketItem {
key: string // Object name/key
uploadId: string // Upload ID of the incomplete upload
size: number // Current size of uploaded parts
}// List all incomplete uploads in bucket
const stream = client.listIncompleteUploads('my-bucket')
stream.on('data', (upload) => {
console.log('Incomplete upload:', upload.key, upload.uploadId, upload.size)
})
stream.on('end', () => console.log('Done listing incomplete uploads'))
stream.on('error', (err) => console.error('Error:', err))
// List incomplete uploads with prefix filter
const prefixStream = client.listIncompleteUploads('my-bucket', 'documents/')
prefixStream.on('data', (upload) => {
console.log('Found incomplete upload for:', upload.key)
})
// List all incomplete uploads recursively
const recursiveStream = client.listIncompleteUploads('my-bucket', '', true)
recursiveStream.on('data', (upload) => {
// Process each incomplete upload
console.log(`Incomplete: ${upload.key} (${upload.size} bytes)`)
})const policy = await client.getBucketPolicy(bucketName)
// Returns: Promise<string> - JSON policy stringawait client.setBucketPolicy(bucketName, policy)
// Parameters
bucketName: string // Bucket name
policy: string // JSON policy string// Read-only public policy
const readOnlyPolicy = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "*"},
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::my-bucket/*"]
}
]
}
await client.setBucketPolicy('my-bucket', JSON.stringify(readOnlyPolicy))
// Full public access policy
const publicPolicy = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "*"},
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": ["arn:aws:s3:::my-bucket/*"]
}
]
}
await client.setBucketPolicy('my-bucket', JSON.stringify(publicPolicy))const tags = await client.getBucketTagging(bucketName)
// Returns: Promise<Tag[]>await client.setBucketTagging(bucketName, tags)
// Parameters
bucketName: string // Bucket name
tags: Tags // Tag collectionawait client.removeBucketTagging(bucketName)interface Tag {
Key: string // Tag key
Value: string // Tag value
}
type Tags = Record<string, string> | Tag[] | TagList
interface TagList {
TagSet: Tag[]
}// Set tags using object syntax
await client.setBucketTagging('my-bucket', {
'Environment': 'production',
'Team': 'backend',
'Project': 'api-storage'
})
// Set tags using Tag array
await client.setBucketTagging('my-bucket', [
{ Key: 'Environment', Value: 'production' },
{ Key: 'Team', Value: 'backend' }
])
// Get and display tags
const tags = await client.getBucketTagging('my-bucket')
tags.forEach(tag => {
console.log(`${tag.Key}: ${tag.Value}`)
})const versionConfig = await client.getBucketVersioning(bucketName)
// Returns: Promise<BucketVersioningConfiguration>await client.setBucketVersioning(bucketName, versionConfig)
// Parameters
bucketName: string // Bucket name
versionConfig: BucketVersioningConfiguration // Versioning settingsinterface BucketVersioningConfiguration {
Status?: 'Enabled' | 'Suspended' // Versioning status
MfaDelete?: 'Enabled' | 'Disabled' // MFA delete requirement
}// Enable versioning
await client.setBucketVersioning('my-bucket', {
Status: 'Enabled'
})
// Suspend versioning (existing versions preserved)
await client.setBucketVersioning('my-bucket', {
Status: 'Suspended'
})
// Check current versioning status
const config = await client.getBucketVersioning('my-bucket')
console.log('Versioning status:', config.Status)const lifecycleConfig = await client.getBucketLifecycle(bucketName)
// Returns: Promise<LifecycleConfig | null>await client.setBucketLifecycle(bucketName, lifeCycleConfig)
// Parameters
bucketName: string // Bucket name
lifeCycleConfig: LifeCycleConfigParam // Lifecycle rulesawait client.removeBucketLifecycle(bucketName)interface LifeCycleConfigParam {
Rule: LifecycleRule[]
}
interface LifecycleRule {
ID?: string // Rule identifier
Status: 'Enabled' | 'Disabled' // Rule status
Filter?: { // Object filter
Prefix?: string // Prefix filter
Tag?: Tag // Tag filter
And?: { // Multiple filters
Prefix?: string
Tags?: Tag[]
}
}
Expiration?: { // Object expiration
Days?: number // Days after creation
Date?: string // Specific date
ExpiredObjectDeleteMarker?: boolean
}
NoncurrentVersionExpiration?: { // Non-current version expiration
NoncurrentDays: number // Days after becoming non-current
}
AbortIncompleteMultipartUpload?: { // Cleanup incomplete uploads
DaysAfterInitiation: number // Days after upload initiation
}
Transition?: { // Storage class transition
Days?: number // Days after creation
Date?: string // Specific date
StorageClass: string // Target storage class
}
NoncurrentVersionTransition?: { // Non-current version transition
NoncurrentDays: number // Days after becoming non-current
StorageClass: string // Target storage class
}
}// Delete objects after 30 days and cleanup incomplete uploads
const lifecycleConfig = {
Rule: [
{
ID: 'DeleteOldObjects',
Status: 'Enabled',
Filter: { Prefix: 'logs/' },
Expiration: { Days: 30 },
AbortIncompleteMultipartUpload: { DaysAfterInitiation: 7 }
},
{
ID: 'ArchiveData',
Status: 'Enabled',
Filter: { Prefix: 'archive/' },
Transition: { Days: 30, StorageClass: 'GLACIER' }
}
]
}
await client.setBucketLifecycle('my-bucket', lifecycleConfig)const encryptionConfig = await client.getBucketEncryption(bucketName)
// Returns: Promise<EncryptionConfig>await client.setBucketEncryption(bucketName, encryptionConfig?)
// Parameters
bucketName: string // Bucket name
encryptionConfig?: EncryptionConfig // Encryption settings (optional for default AES256)await client.removeBucketEncryption(bucketName)interface EncryptionConfig {
Rule: EncryptionRule[]
}
interface EncryptionRule {
ApplyServerSideEncryptionByDefault: {
SSEAlgorithm: 'AES256' | 'aws:kms' // Encryption algorithm
KMSMasterKeyID?: string // KMS key ID (for KMS encryption)
}
}// Default AES256 encryption
await client.setBucketEncryption('my-bucket')
// Explicit AES256 encryption
const aes256Config = {
Rule: [{
ApplyServerSideEncryptionByDefault: {
SSEAlgorithm: 'AES256'
}
}]
}
await client.setBucketEncryption('my-bucket', aes256Config)
// KMS encryption with specific key
const kmsConfig = {
Rule: [{
ApplyServerSideEncryptionByDefault: {
SSEAlgorithm: 'aws:kms',
KMSMasterKeyID: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012'
}
}]
}
await client.setBucketEncryption('my-bucket', kmsConfig)const replicationConfig = await client.getBucketReplication(bucketName)
// Returns: Promise<ReplicationConfig>await client.setBucketReplication(bucketName, replicationConfig)
// Parameters
bucketName: string // Source bucket name
replicationConfig: ReplicationConfigOpts // Replication settingsawait client.removeBucketReplication(bucketName)interface ReplicationConfigOpts {
Role: string // IAM role for replication
Rule: ReplicationRule[] // Replication rules
}
interface ReplicationRule {
ID?: string // Rule identifier
Status: 'Enabled' | 'Disabled' // Rule status
Priority?: number // Rule priority (higher numbers = higher priority)
DeleteMarkerReplication?: {
Status: 'Enabled' | 'Disabled'
}
Filter?: { // Object filter
Prefix?: string // Prefix filter
Tag?: Tag // Tag filter
And?: { // Multiple filters
Prefix?: string
Tags?: Tag[]
}
}
Destination: {
Bucket: string // Destination bucket ARN
StorageClass?: string // Storage class in destination
ReplicationTime?: { // Replication time control
Status: 'Enabled' | 'Disabled'
Time: { Minutes: number }
}
Metrics?: { // Replication metrics
Status: 'Enabled' | 'Disabled'
EventThreshold: { Minutes: number }
}
}
}const replicationConfig = {
Role: 'arn:aws:iam::123456789012:role/replication-role',
Rule: [{
ID: 'ReplicateAll',
Status: 'Enabled',
Priority: 1,
DeleteMarkerReplication: { Status: 'Enabled' },
Filter: { Prefix: '' }, // Replicate all objects
Destination: {
Bucket: 'arn:aws:s3:::destination-bucket',
StorageClass: 'STANDARD_IA'
}
}]
}
await client.setBucketReplication('source-bucket', replicationConfig)const lockConfig = await client.getObjectLockConfig(bucketName)
// Returns: Promise<ObjectLockInfo>await client.setObjectLockConfig(bucketName, lockConfigOpts)
// Parameters
bucketName: string // Bucket name
lockConfigOpts: Omit<ObjectLockInfo, 'objectLockEnabled'> // Lock configurationinterface ObjectLockInfo {
objectLockEnabled: 'Enabled' | 'Disabled' // Object lock status (read-only)
rule?: { // Default retention rule
defaultRetention: {
mode: RETENTION_MODES // Governance or Compliance
days?: number // Retention period in days
years?: number // Retention period in years
validity?: RETENTION_VALIDITY_UNITS // DAYS or YEARS
}
}
}import { RETENTION_MODES, RETENTION_VALIDITY_UNITS } from 'minio'
// Note: Object locking must be enabled during bucket creation
await client.makeBucket('locked-bucket', 'us-east-1', {
ObjectLocking: true
})
// Set default retention rule
await client.setObjectLockConfig('locked-bucket', {
rule: {
defaultRetention: {
mode: RETENTION_MODES.GOVERNANCE,
days: 30,
validity: RETENTION_VALIDITY_UNITS.DAYS
}
}
})
// Check configuration
const lockInfo = await client.getObjectLockConfig('locked-bucket')
console.log('Object lock enabled:', lockInfo.objectLockEnabled)
console.log('Default retention:', lockInfo.rule?.defaultRetention)See Notifications for detailed documentation on bucket notification configuration.
import { S3Error, InvalidBucketNameError } from 'minio'
try {
await client.makeBucket('invalid..bucket..name')
} catch (error) {
if (error instanceof InvalidBucketNameError) {
console.error('Invalid bucket name:', error.message)
} else if (error instanceof S3Error) {
console.error('S3 Error:', error.code, error.message)
}
}Next: Object Operations - Learn about basic object CRUD operations