Kensio Software Blog »

@kensio/yulin TypeScript AWS simulator npm package

Hugh Grigg | Kensio Software | Sunday 7 Jun 2026

The @kensio/yulin package is an AWS simulator for Node.js TypeScript applications. It’s conceptually related to moto for Python and LocalStack, but is a bit different to both of those.

Yulin simulates AWS services entirely in-process, allowing tests and local development environments to interact with realistic AWS behaviour without requiring real AWS infrastructure, Docker containers or any i/o at all.

This differs from traditional test mocking by simulating internal state and overall behaviour. Traditional mocks don’t tend to provide a lot of value, and often end up being detrimental by requiring so much repetitive boilerplate.

The same Yulin configuration can be shared between tests and local development servers, so you can define your AWS simulation once and then use it for both those purposes. Because it all runs in the same single-threaded Node.js process, you can step through the whole system (AWS plus your applications) in the debugger. This also means you can bring in other testing tools like nock HTTP interception and vitest fake timers.

Yulin is still in an early stage and currently only simulates a small subset of AWS services and behaviours. The long-term goal is to allow simulating multiple complex applications that involve several AWS services together, such as S3, CloudFront, SQS, DynamoDB and Lambda.

Simulate, don’t mock

There are already several ways to test AWS-based applications.

At one end of the spectrum are traditional pure unit tests with heavy mocking of dependencies. These are usually fast, but the mocking tends to be fragile and difficult to maintain. A Lambda that writes to DynamoDB might be tested by mocking the DynamoDB client and asserting that a particular method was called with particular arguments. Any time there’s a change related to that, the tests and mocks have to be meticulously updated.

That kind of test can be useful, but they only verify a narrow slice of the overall system behaviour. They also tend to become brittle, as implementation details leak into the tests, and the mocks cannot keep up with ongoing changes to the system design.

At the other end of the spectrum are integration tests running against real AWS infrastructure. In theory, these can provide much stronger confidence, but they are slower, more expensive and require even more setup and maintenance. They are also at least as fragile as pure unit tests with mocks, but in a different way. Integration tests are prone to false positives due to networking issues, cold-starts and asynchronous behaviour.

Tools like LocalStack do bridge the gap between those two extremes, but in practice they often require even more setup and configuration than integration tests that hit real AWS infrastructure.

Many systems would benefit from tests that exercise realistic interactions between AWS services while still remaining fast, isolated and easy to run locally.

Simulating AWS behaviour

Yulin takes the approach of simulating AWS services directly inside the Node.js process, while avoiding magic and clever tricks.

A test can create a simulated AWS environment, configure services and then execute application code against that environment. Everything runs in memory and within the same process.

Because there is no real networking involved, tests remain fast. There are no containers to start, no infrastructure to provision and no external dependencies to coordinate.

This also makes local development easier. The same simulated environment can be used both by automated tests and for running the system locally and interacting with it via localhost.

Testing systems instead of method calls

One benefit of this approach is that it shifts the focus of testing away from implementation details and towards meaningful system behaviour.

Rather than asserting that a particular SDK method was called, a test can exercise a larger workflow and verify the resulting system state.

For example, a test might verify that a Lambda processes an event correctly, updates data in DynamoDB and publishes the expected messages to SQS. The exact implementation details are often less important than whether the overall behaviour is correct.

This kind of testing tends to align more closely with the behaviours that users and stakeholders actually care about.

Local development

As a software engineering contractor, I see a lot of teams struggle or give up with getting their system to run locally on engineers’ laptops. That then leads to contention on development environments in AWS, which are also expensive to operate and maintain.

More importantly, there is a large hidden cost when engineers cannot iterate rapidly on the applications they are building. If deploying to AWS is the only option for properly testing changes, the development iteration cycle gets bogged down, and before long one cycle can take hours or even days. If it’s possible to run the system locally on your laptop, that can instead be minutes or seconds.

To solve that problem, Yulin can expose on localhost the simulated AWS services and the applications running amongst them. This allows other local applications, development tools and browsers to interact with applications in the simulated AWS environment using realistic endpoints and behaviours.

One small example is static website hosting via S3. Yulin can serve a simulated S3 website locally while still supporting S3 website features such as routing rules, redirects and error documents. That is integrated with the rest of the simulation, so you can have a DynamoDB stream trigger a Lambda function that writes an object to an S3 website bucket. You can then view the resulting web page in your browser on localhost.

Using the same configuration for local development and automated tests can help reduce duplication and make development environments more representative of production behaviour.

Early stages

I have to emphasise that Yulin is still a work in progress. Only a small subset of AWS services and behaviours are implemented so far, and Yulin’s APIs will evolve as the project progresses. The focus at this stage is implementing the behaviours that I happen to need for my own projects.

Even in its current minimal state, Yulin is already useful to me for quickly iterating and testing on projects.

GitHub:

https://github.com/KensioSoftware/yulin

npm:

https://www.npmjs.com/package/@kensio/yulin