My Java code stores files in S3 and data in DynamoDB. How do I develop and try it on my machine, without an AWS account, without a bill, and without changing the code that talks to AWS?

This post introduces Floci, a local AWS emulator, with an end-to-end example: the AWS CLI creates the resources, a small Java application uses them, and the Floci web console shows them. I contribute to the Floci project.

Why a local emulator

To try code that talks to AWS, you can use a real account: you need credentials, each call can cost money, and a configuration mistake can touch more than a test environment. A local emulator answers the same calls, on the machine, with no account and no bill.

LocalStack is the best-known tool in this field. Since March 2026, according to its own blog, it ships as a single image that needs an auth token, with a free account-based plan for individuals and open source projects. Floci works with no account and no token.

Floci in brief

According to its README, Floci is “a free, open-source local AWS emulator for development, testing, and CI”, under the MIT license. It is part of a family of emulators: floci for AWS (port 4566), and others for Azure, GCP and OCI.

All AWS services answer on http://localhost:4566. Any published region works, and the credentials can be any non-empty values.

An emulator, not a mock

In a test, a mock replaces the AWS client with a fake object. It answers what you told it to answer. The code makes no network call, and the test mostly checks what you believe about AWS.

Floci is something else: it is a server that speaks the AWS protocol. The code keeps the real AWS client (the one of the AWS CLI, the Java SDK, Terraform…), which sends real HTTP requests, signed like for AWS. Only the address changes: localhost instead of AWS.

The README describes its architecture:

  • an HTTP router receives the requests in the AWS format;
  • stateless services (SQS, SNS, IAM, STS, KMS, Secrets Manager…);
  • stateful services: S3, DynamoDB and DynamoDB Streams;
  • services that start real Docker containers: Lambda, RDS, ElastiCache, MSK, ECS, EC2, EKS…;
  • the storage of your choice: in memory, persistent, hybrid, or with a write-ahead log.

Floci measures its compatibility with test suites per SDK and per tool, published in its repository: for example 1,326 tests for the AWS SDK for Java v2, 205 for the AWS CLI v2, 67 for Terraform.

Start Floci

The simplest way is its CLI, floci-cli (Docker must be running):

floci start
floci status

Floci then runs in a container and answers on port 4566.

With the AWS CLI

floci env prints the variables that send the AWS CLI to Floci:

export AWS_ENDPOINT_URL='http://localhost.floci.io:4566'
export AWS_ACCESS_KEY_ID='test'
export AWS_SECRET_ACCESS_KEY='test'
export AWS_DEFAULT_REGION='us-east-1'

localhost.floci.io is a name that points to 127.0.0.1, like its subdomains: documents.localhost.floci.io too. This is useful for S3, which can put the bucket name in the host name.

I create the resources of the example: a bucket for the texts, a table for the info.

eval "$(floci env)"
aws s3 mb s3://documents
aws dynamodb create-table \
  --table-name document-info \
  --attribute-definitions AttributeName=id,AttributeType=S \
  --key-schema AttributeName=id,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

To see that the CLI does nothing special, the --debug option shows the request:

aws s3 ls --debug
Endpoint provider result: http://localhost.floci.io:4566
Sending http request: <AWSPreparedRequest ... method=GET, url=http://localhost.floci.io:4566/,
  headers={... 'Authorization': b'AWS4-HMAC-SHA256 Credential=test/..., SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=...' ...}>
Response headers: {'Content-Type': 'application/xml', ..., 'x-amz-request-id': '9f476e72-...'}

(I shortened the lines.) The request is signed with SigV4 (AWS4-HMAC-SHA256), exactly like for AWS, and Floci answers in XML, like S3. So that you do not export these variables in each terminal, a named AWS profile does the same; I explain it in the post about my dev machine.

With the Java SDK

The example is a small application, published on GitLab: floci-aws-local-demo. It stores « documents »: the text in S3, the info (title, author) in DynamoDB, and the consultation returns both together. It uses the AWS SDK for Java v2; Quarkus is only the web layer.

EndpointWhat it doesAWS service
POST /documents (text)stores the text, returns an idS3
POST /documents/{id}/info (JSON)stores the title and the authorDynamoDB
GET /documents/{id}returns the info and the textDynamoDB + S3
GET /documentslists the documentsDynamoDB

It is an educational example: each class builds its client with visible constants. The S3 client (a simplified part of DocumentTextResource.java):

private static final URI ENDPOINT = URI.create("http://localhost:4566");
private static final Region REGION = Region.US_EAST_1;
// Floci accepts any non-empty credentials.
private static final AwsBasicCredentials CREDENTIALS = AwsBasicCredentials.create("test", "test");

try (S3Client s3 = S3Client.builder()
        .endpointOverride(ENDPOINT)
        .region(REGION)
        .credentialsProvider(StaticCredentialsProvider.create(CREDENTIALS))
        .build()) {

    PutObjectRequest request = PutObjectRequest.builder()
            .bucket("documents")
            .key(id + ".txt")
            .contentType(MediaType.TEXT_PLAIN)
            .build();
    s3.putObject(request, RequestBody.fromString(text));
}

This is the S3 client you would use with AWS. The only difference is endpointOverride: with real AWS, you remove this line and use real credentials. The DynamoDB client is built the same way, in DocumentInfoResource.java.

The application runs on the machine, with the Java and Maven versions given by its mise.toml file:

mise install
mvn quarkus:dev

Then you store a document and its info, and read it back:

curl -X POST localhost:8080/documents -H 'Content-Type: text/plain' \
  --data 'Floci speaks the AWS protocol on port 4566.'
{"id":"3fa7b64a-10e9-4e1e-b9d3-258a043f8122"}
curl -X POST localhost:8080/documents/3fa7b64a-10e9-4e1e-b9d3-258a043f8122/info \
  -H 'Content-Type: application/json' -d '{"title":"Hello Floci","author":"Foulen Foulani"}'
curl localhost:8080/documents/3fa7b64a-10e9-4e1e-b9d3-258a043f8122
{"id":"3fa7b64a-…","title":"Hello Floci","author":"Foulen Foulani","createdAt":"2026-10-24T03:12:58.387781Z","text":"Floci speaks the AWS protocol on port 4566."}

The title comes from DynamoDB, the text from S3. An unknown id answers 404.

Here, the Floci address is a constant in the code. In a real project, you can keep it out of the code: according to the AWS guide, the SDK for Java 2.x reads AWS_ENDPOINT_URL, or endpoint_url in an AWS profile (the SDK 1.x does not).

The web console

Floci has a web console: http://localhost:4566/_floci/ui. It does not run at startup. On the first visit, Floci starts a container next to it, with the console, then redirects the browser there (here, to port 4500). This is why Floci needs the Docker socket (floci start takes care of it). The console does more than show: you can also create a bucket, upload a file, add an item to a table or run a PartiQL query.

The home page of the Floci web console: the available AWS services and the number of resources of each one.

The documents bucket holds the text stored by the application:

In the Floci console, the documents bucket: its details on the right, and at the bottom its file 3fa7b64a-….txt of 43 bytes.

And the document-info table holds its info. A PartiQL query shows it as JSON:

In the Floci console, the document-info table with the item of Foulen Foulani, and the result of the PartiQL query SELECT * FROM document-info: createdAt, author, id and title.

What to know

An emulator is not AWS. Floci reproduces the protocol and the behavior of the services, and its test suites measure this compatibility; but for a given service, check its place in the list of services and in these tests. The services that start real containers (Lambda, RDS…) need Docker.

To go further, Floci also has Testcontainers modules (Java, Node.js, Python, .NET) that start an isolated Floci for each test. Testing your code with Floci will be the topic of a next post.

Tested on macOS with Floci 2.3.0 (CLI 0.4.0), the AWS CLI 2.38.5, Java 21 (Temurin 21.0.13), Quarkus 3.40.1.1 and the AWS SDK for Java 2.46.7.

Sources: the Floci README (introduction, architecture, web console, compatibility tests, Testcontainers), floci-cli, LocalStack’s post about the delivery of its emulators, and the AWS guide on endpoints.

Further reading