A small Amazon Kinesis Data Streams emulator written in Rust.
Configure your AWS SDK to use http://localhost:4567 with dummy credentials.
It implements the ten Kinesis Data Streams operations that PutRecord producers and polling consumers use.
A single static binary with no JVM, Node.js or Python runtime underneath: it starts in milliseconds and idles at a few MB of RAM.
docker run --rm -p 4567:4567 ghcr.io/pafin-inc/fakestream
The problem
LocalStack serves Kinesis from inside the full LocalStack container: a Python control plane plus a Node.js engine, or a JVM if you enable the Scala engine for throughput. In our local stack it used several hundred MB before the first record arrived, and the JVM engine wanted a multi-GB heap.
As of March 2026 LocalStack also requires an account and an auth token, and its free tier is limited to non-commercial use.
fakestream was written for teams whose applications only need the Kinesis polling APIs.
Starts in milliseconds, so restarting it between test runs or on every file change is cheap.
Each CI job can run its own instance. Memory is a few MB idle and grows with the records it retains.
A single process serving one API, with no control plane or other service emulators alongside it.
Set the endpoint override in local and CI configuration only. Production configuration is not touched.
Keep LocalStack or real AWS for everything else. Current AWS SDKs and the CLI read AWS_ENDPOINT_URL_KINESIS, so only Kinesis traffic is redirected; older SDKs take the endpoint on the Kinesis client instead.
By the numbers
Measured on a developer laptop with a replay of pafin's own ingestion traffic (large batched records), at about 12× that pipeline's peak rate; the load generator never saturated the server. Numbers will differ on your hardware.
Features
Any client that speaks AWS JSON 1.1 works with an endpoint override and dummy credentials; Java SDKs need CBOR turned off. Implemented: CreateStream, DeleteStream, PutRecord, PutRecords, GetRecords, GetShardIterator (all five iterator types), DescribeStream, DescribeStreamSummary, ListShards and ListStreams.
A small fixed thread pool and one RwLock<Store>, no async runtime. A few MB idle; beyond that, memory tracks the bytes held in streams plus per-record overhead, and shrinks as records expire.
--persist <dir> turns on a segmented write-ahead log, so records survive a restart. A hard crash can lose records written since the last maintenance tick (5 s by default). In our benchmark it cost about 8% of PutRecord throughput.
1 MiB record and 5 MiB batch limits, 5-minute iterator expiry, 10 MiB GetRecords responses. Requests that exceed them fail in local tests rather than in production. Per-shard throughput limits are not enforced.
--retention-hours sets the default retention for streams created without one. --ttl-seconds overrides it precisely, and 0 keeps records forever.
A musl-linked Rust executable with no JVM, Node.js or Python runtime to install, also published as a Docker image for linux/amd64 and linux/arm64. Configuration is a handful of flags or environment variables.
How it works
POST / with X-Amz-Target: Kinesis_20131202.<Op> and application/x-amz-json-1.1 — the same request the AWS SDK sends to the real service, handled directly.
Each partition key is hashed to a 128-bit MD5 value and the record goes to the shard whose contiguous hash-key range contains it, as in Kinesis. A single global counter assigns increasing sequence numbers.
fakestream issues shard iterators; durable checkpoints stay in your consumer (DynamoDB with KCL-style pollers, in-process in tests), as with real Kinesis. KCL lease coordination is not implemented.
Quickstart
PutRecord, PutRecords, GetShardIterator and GetRecords behave as they do against Kinesis. Java clients need the CBOR setting from the FAQ.
FAQ
CreateStream, DeleteStreamListStreams, DescribeStream, DescribeStreamSummary, ListShardsPutRecord, PutRecordsGetShardIterator with TRIM_HORIZON, LATEST, AT_SEQUENCE_NUMBER, AFTER_SEQUENCE_NUMBER, AT_TIMESTAMPGetRecordsThe tested path is PutRecord or PutRecords, then GetShardIterator and repeated GetRecords.
Using --persist <dir> enables a segmented write-ahead log (WAL) that survives process restarts.
Without the flag, records exist only in process memory and are discarded when the process exits.
In our benchmark, persistence cost about 8% of PutRecord throughput.
fakestream emulates only Kinesis Data Streams. LocalStack can keep serving SQS, DynamoDB, S3 and the rest.
Point only AWS_ENDPOINT_URL_KINESIS at fakestream. Optionally narrow LocalStack with SERVICES=dynamodb,... so it no longer starts its own Kinesis.
Yes, once CBOR is turned off. The Java SDKs default to application/x-amz-cbor-1.1, which fakestream does not speak.
AWS_CBOR_DISABLED=trueCBOR_ENABLED=falseEvery client still needs the endpoint override. Python, JavaScript, Go and the AWS CLI need nothing beyond that.
SubscribeToShard)SplitShard, MergeShards, UpdateShardCount)fakestream is built for local development and CI. Run it on a trusted network only: localhost, a CI job, or a private container network.
MIT licensed. Images for linux/amd64 and linux/arm64 on GHCR; port 4567; in-memory unless --persist is set.