If you build against S3, you have two unappealing options for local dev: spend money calling AWS, or run something that emulates S3 on your machine. MinIO is the second option done well — a single Go binary that speaks the S3 API and has its own web console. Point the AWS SDK at it instead of s3.amazonaws.com and most of your code doesn't know the difference.
How do I run MinIO in Docker?
docker run -d --name minio \
-p 9000:9000 -p 9001:9001 \
-e MINIO_ROOT_USER=minio-admin \
-e MINIO_ROOT_PASSWORD=minio-password \
-v minio-data:/data \
quay.io/minio/minio \
server /data --console-address ":9001"S3 API on http://localhost:9000, console on http://localhost:9001. Log in to the console with minio-admin / minio-password, create a bucket, get access/secret keys.
Configure ports, credentials, and the data volume.
Why a volume on /data
MinIO stores object data, bucket metadata, and config under /data. Without a volume mount there, every docker rm wipes your buckets. The volume keeps the data alive:
docker stop :container_name && docker rm :container_name
docker run -d --name :container_name \
-p :s3_port:9000 -p :console_port:9001 \
-e MINIO_ROOT_USER=:user \
-e MINIO_ROOT_PASSWORD=:password \
-v minio-data:/data \
quay.io/minio/minio \
server /data --console-address ":9001"
# Buckets and objects are still there.Practical usage: point the AWS SDK at MinIO
For a Node app using @aws-sdk/client-s3:
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
const s3 = new S3Client({
endpoint: 'http://127.0.0.1:9000', // MinIO instead of s3.amazonaws.com
region: 'us-east-1', // arbitrary, but required
credentials: {
accessKeyId: 'YOUR-MINIO-ACCESS-KEY',
secretAccessKey: 'YOUR-MINIO-SECRET-KEY',
},
forcePathStyle: true, // MinIO uses path-style URLs
});
await s3.send(new PutObjectCommand({
Bucket: 'my-bucket',
Key: 'hello.txt',
Body: 'Hello from MinIO',
}));Three things to know:
endpointpoints at MinIO's S3 port instead of AWS.forcePathStyle: true— MinIO useshttp://host:port/bucket/keyURLs, not the virtual-host style AWS prefers (bucket.host:port/key). Without this flag, modern AWS SDKs default to virtual-host style and MinIO refuses.regionis required but unused. Anything works.
For Python boto3:
import boto3
s3 = boto3.client(
's3',
endpoint_url='http://127.0.0.1:9000',
aws_access_key_id='YOUR-MINIO-ACCESS-KEY',
aws_secret_access_key='YOUR-MINIO-SECRET-KEY',
region_name='us-east-1',
)
s3.put_object(Bucket='my-bucket', Key='hello.txt', Body=b'Hello')Same idea — different SDK, same MinIO. Once your app talks to MinIO locally, the only thing that changes when you point it at real AWS is the endpoint and credentials.
Generate access keys
The MINIO_ROOT_USER / MINIO_ROOT_PASSWORD env vars are the admin login for the console. For actual S3-API calls, generate access keys per application:
- Log into the console (
http://localhost::console_port). - Navigate to Identity → Access Keys → Create Access Key.
- Copy the access key and secret. The secret is shown only once.
Use those keys in your app's SDK config.
Compose example
services:
minio:
image: quay.io/minio/minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: :user
MINIO_ROOT_PASSWORD: :password
ports:
- "::s3_port:9000"
- "::console_port:9001"
volumes:
- minio-data:/data
restart: unless-stopped
volumes:
minio-data:Common pitfalls
- No volume on
/data. Buckets and objects die with the container. - AWS SDK using virtual-host URLs. MinIO speaks path-style by default; turn on
forcePathStyle: trueor--addressing-style pathdepending on the SDK. MINIO_ACCESS_KEY/MINIO_SECRET_KEYenv vars. Those names worked in older MinIO releases. Current MinIO usesMINIO_ROOT_USER/MINIO_ROOT_PASSWORD.- Connecting from a container. Inside Docker, MinIO is reachable via the service name (
minio:9000), not127.0.0.1. Theendpointin your SDK depends on whether the calling app runs on the host or in a sibling container. - HTTPS in dev. MinIO can do TLS but the dev pattern is plain HTTP. Don't waste time on certs locally; if your prod code requires HTTPS, configure that conditionally.
What to do next
- How to Dockerize a Node.js App — pair MinIO with a Node app in Compose.
- Docker Volumes vs Bind Mounts — the full picture on the volume choice.
FAQ
Sources
Authoritative references this article was fact-checked against.
- MinIO official image — Docker Hubhub.docker.com
- MinIO container documentationmin.io

