Library / SDK
getmoto/moto avatar
getmoto/moto

Moto: mocking AWS in Python tests without an AWS account

A library that allows you to easily mock out tests based on AWS infrastructure.

8,687 stars2,258 forksPythonApache-2.0

At a glance

What is it?
Moto intercepts boto3 calls inside your test process and keeps the state in memory. It is the right tool when you want fast unit tests for AWS code, and the wrong one when you need to test IAM, networking or anything the mock does not implement.
Who is it for?
Adopt Moto if your tests exercise boto3 client and resource calls and you want them to run in-process with no credentials and no network. Do not adopt it if your test needs real IAM evaluation, VPC networking, or a service that is missing from IMPLEMENTATION_COVERAGE.md, and do not treat a green Moto test as proof that the same call succeeds against AWS.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Moto removes from a boto3 test suite

Code that talks to AWS is awkward to test. Every test needs credentials, a region, a bucket or queue that already exists, and a cleanup step so the next run starts from the same state. Pointing tests at a real account makes the suite slow, costs money, and turns a flaky network into a flaky build. The usual workaround is to wrap the boto3 client in a hand-written stub, which means writing and maintaining a fake for every method you call.

Moto takes that work away. The README describes it as "a library that allows your tests to easily mock out AWS Services", and the mechanism is a decorator: you annotate a test function with @mock_aws, and inside that function every boto3 call is served by Moto instead of by AWS. The audience is Python developers whose production code already uses boto3, and who want the test suite to run on a laptop or a CI runner with no AWS account attached. If your code is not Python, or does not go through boto3, this library does not apply to you.

How the mock intercepts boto3 calls and keeps state

The decorator is the whole interface. When the wrapped function starts, Moto patches the boto3 and botocore layers so that requests are answered locally; when the function returns, the patch is removed. Nothing listens on a socket in the default mode, which is why the tests need no credentials and no region configuration beyond what boto3 itself demands.

State lives in memory for the duration of the decorated function. The README is explicit that this is a fresh account rather than a mirror of yours: "We need to create the bucket since this is all in Moto's 'virtual' AWS account". So a test that calls put_object against a bucket must call create_bucket first, even if that bucket exists in the real account. Between tests the state is gone, which is the point: no teardown script, no leftover resources, no ordering dependency.

The repository also ships a server form. The Dockerfile installs the package with the server extra and sets ENTRYPOINT to moto_server with -H 0.0.0.0, exposing port 5000. That mode is for code that cannot be patched in-process, such as another language's SDK, and the other_langs directory in the repository layout is there to hold examples. The trade-off is real: the server is a separate process, so tests that use it are slower and need the container running before the suite starts.

Installing Moto and writing a first mocked test

Installation is a single pip command. The extras select the services you want to mock; the README shows the bracket form with ec2, s3 and all.

bash
pip install 'moto[ec2,s3,all]'

Installing every service is convenient but pulls in the full dependency set. If your tests only touch S3, listing just that extra keeps the install smaller.

The README's own example is the fastest way to see the pattern. The code under test puts an object into a bucket, and the test creates the bucket first because Moto starts from an empty virtual account.

python
import boto3
from moto import mock_aws
from mymodule import MyModel


@mock_aws
def test_my_model_save():
    conn = boto3.resource("s3", region_name="us-east-1")
    conn.create_bucket(Bucket="mybucket")
    model_instance = MyModel("steve", "is awesome")
    model_instance.save()
    body = conn.Object("mybucket", "steve").get()["Body"].read().decode("utf-8")
    assert body == "is awesome"

Run it with pytest as usual. What you should see is a passing test with no network traffic. If it fails with a missing bucket, you forgot the create_bucket call, which is the most common first mistake with this library.

Where Moto stops being the right tool

Coverage is per service and per API call, and the repository tracks it in IMPLEMENTATION_COVERAGE.md rather than in the README. That file is the honest answer to "does Moto support X", and it changes between releases, so a service that was thin in 5.2.1 may have grown by 5.2.3. The practical failure mode is a test that passes locally because the call you made is implemented, then fails in a staging environment because the real service validates something the mock ignores.

Behavioural fidelity is the second limit. A mock cannot enforce IAM policy evaluation, VPC routing, service quotas, or eventual consistency in the way the real service does. Tests that exist to prove a permission boundary works will pass under Moto and tell you nothing. The same applies to anything that depends on AWS-side timing or throttling.

The pytest markers in pyproject.toml hint at the boundary the maintainers themselves draw. There are markers for network, requires_docker, aws_verified and requires_clean_slate, which means parts of the test suite are expected to run against real AWS or in isolation rather than under the default in-process mock. If your project needs that class of verification, Moto is one layer of your test strategy, not the whole of it.

Moto against LocalStack: in-process mock or a local cloud

The comparison people reach for is Moto versus LocalStack. The difference is architectural. Moto patches boto3 inside the Python process, so a test is a function call away from the mock and the state disappears when the function ends. LocalStack runs as a separate service that you point your endpoint URL at, which means any language and any SDK can talk to it, and the state survives across processes until you reset it.

That makes LocalStack the better fit when you want to exercise a container or a CLI against AWS-shaped endpoints, or when your code is not Python. Moto is the better fit when the goal is a fast unit test inside an existing pytest suite with no extra process to start. Moto does offer a server mode through moto_server on port 5000, which narrows the gap, but the default and best-supported path remains the decorator.

A second alternative is to stub boto3 yourself with unittest.mock. That gives you exact control over return values, and it also means you assert against your own assumptions rather than against anything that resembles AWS. Moto's state tracking, where a put_object is visible to a later get_object, is the part you would have to rebuild by hand.

Licence, releases and the cost of upgrading

Moto is Apache-2.0, which permits commercial use and modification; the repository ships the LICENSE file at the top level. That is a permissive licence, but it is not legal advice, and if you redistribute the library inside a product you should read the terms yourself.

Release cadence is visible in the version history: 5.2.1 on 2026-05-10, 5.2.2 on 2026-06-06, 5.2.3 on 2026-08-22, and the last push to the default branch was on 2026-09-21. The project is not archived. Upgrades are the cost to plan for. Because Moto tracks AWS API behaviour, a new release can change a response shape or add validation that your tests were previously passing without. Pinning the version in your dependency file and reading CHANGELOG.md before bumping is the cheap way to avoid a surprise red build.

There is one packaging detail worth knowing because it affects what you debug. setup.py defines a CompressJsonCommand that gzips JSON files during a binary distribution build and deletes the originals. If you are inspecting an installed wheel for data files, expect .json.gz rather than plain .json.

Editorial conclusion

Adopt Moto if your tests exercise boto3 client and resource calls and you want them to run in-process with no credentials and no network. Do not adopt it if your test needs real IAM evaluation, VPC networking, or a service that is missing from IMPLEMENTATION_COVERAGE.md, and do not treat a green Moto test as proof that the same call succeeds against AWS. Before committing to it, open IMPLEMENTATION_COVERAGE.md and check the specific API calls your code makes, then run one of your existing integration tests under @mock_aws and see whether it passes for the right reason.

Frequently asked questions

Does Moto need an AWS account or credentials?

No. The README's example test runs with only a region name passed to boto3, and the mock keeps its own state during the decorated function. The bucket has to be created inside the test because Moto starts from an empty virtual account.

How do I install Moto for S3 and EC2 tests?

The README gives the command pip install 'moto[ec2,s3,all]', where the extras select the services to mock. Installing all of them is the simplest option; selecting only the extras you use keeps the dependency set smaller.

Can I run Moto as a server instead of using the decorator?

Yes. The repository Dockerfile installs the server extra and sets the entrypoint to moto_server with -H 0.0.0.0, exposing port 5000. That mode is aimed at code that cannot be patched in-process, such as another language's SDK.

Which AWS services and API calls does Moto implement?

The README points to IMPLEMENTATION_COVERAGE.md in the repository for the full list of covered services and features. Coverage is tracked per service and changes between releases, so check that file against the calls your tests make.

Official sources

  1. getmoto/moto on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/getmoto-moto.svg)](https://hysenlabs.com/projects/getmoto-moto)