v0.1.0 · open source · Apache-2.0

Run AWS Lambda, SQS and DynamoDB locally — without Docker

The dev server AWS Lambda never had. Your whole app — API, queues, workers, tables — running natively on your laptop in 99 milliseconds.

~/shop — the whole looplive
$ pulse init shop -t api-and-worker --lang python
created project shop · installing dependencies — done (6.6s)
$ pulse start
functions createOrder · getOrder · worker api http://localhost:3000 routes POST /orders createOrder ready in 99ms — code & pulse.yaml changes apply live
$ curl -X POST localhost:3000/orders -d '{"sku":"A1","qty":2}'
201 {"id":"e9b4…","status":"pending"} ⚙ sqs order-events → worker · batch of 1 · ok 🎉 first background job processed — your async loop works end to end
0ms
Engine ready
containers: 10–30 s
0ms
Warm invoke
no cold containers
0 MB
Total memory
Docker stacks: 2 GB+
$0
To learn & build
no AWS account needed
measured on every CI run — a slower pulse is a failed build ↗
01 features

A local cloud that keeps up with your typing

No containers to build, no orchestration to debug. Just your app, running.

sqs · retries · dlq

Push to a queue, handle it in a worker

You never call a worker yourself. pulse watches the queue and delivers.

  • Visibility timeouts and automatic retries
  • Dead-letter queue when it keeps failing
  • The one thing sam local can't do at all
POST /ordersworker ✓
pulse start
⚙ sqs order-events → worker · batch of 1 · ok worker | processed order 9de0… worker ! RuntimeError (attempt 1) worker ! RuntimeError (attempt 2) ☠ moved to order-events-dlq after 3 receives
hot reload

Build & run Lambdas, measured in milliseconds

Save a file. The next request runs the new code. Restarts don't exist here.

  • Real Lambda Runtime API, as a native process
  • Plain boto3 or SDK v3 — no pulse imports
  • pulse.yaml edits apply live too
⌘S handler.py saved
hot reload: worker (1 change)
next invoke · 17 ms
handler.py
import boto3 table = boto3.resource("dynamodb").Table("orders") def handler(event, context): return {"statusCode": 200} # local → AWS_ENDPOINT_URL set for you # prod → same code, talks to AWS

Time travel debugging

Replay yesterday's crash against today's fix — byte for byte.

Runs like AWS

Real wire protocols throughout — the AWS SDK can't tell the difference.

A CLI that teaches

Run any command bare and it asks instead of erroring. Errors ship their fix.

02 how it works

One engine, entirely on your laptop

One native process, one SQLite file. Four steps from empty folder to replayable request.

01

Spin up the dev loop

Working handlers, a pulse.yaml, dependencies installed. Then the API, queues and tables all come online together.

$ pulse init shop -t api-and-worker && pulse start
02

Call it over plain HTTP

Your route becomes a real API Gateway event — path params, query strings, body, exactly like production.

$ curl -X POST localhost:3000/orders -d '{"sku":"A1"}'
03

Let a worker finish the job

Your handler queues a message and replies immediately; pulse delivers it, retries failures and dead-letters repeat offenders.

$ pulse send order-events '{"id":"e9b4"}'
04

Replay whatever broke

Every payload is recorded. Fix the handler, re-fire the actual event against your current code, watch it pass.

$ pulse events replay 8931cf5b
03 debugging

You never lose the event that broke it

Logs are where debugging starts, not where it ends. Four ways to see what actually happened.

pulse logs --request d90e5295
$ pulse logs --request d90e5295 ⚡ request d90e5295 sqs processWebhook · error · 2ms · 00:08 event { "Records": [ { …the exact payload that arrived, pretty-printed… } … 6 more line(s) logs 00:08:15.903 stderr Traceback (most recent call last): … error RuntimeError: webhook 3625d493 failed on purpose (attempt 3) re-run it against your current code: pulse events replay d90e5295

One id, the whole story: the exact payload that arrived, everything the function printed, how it ended — and the command to re-run it.

04 compare

Built for the inner loop

LocalStack tests your infra. SAM deploys. pulse owns the five hundred iterations before staging.

Featurepulsesam localLocalStack
Cold start to working~100 mscontainer per invoke10–30 s container
Code changesave → donemostly re-invokeredeploy / config
Queue → worker → DLQ locally out of the boxnot availablevia deploy cycle
Event replay & request stories built in
Requirementsone 20 MB binaryDockerDocker, GB-scale image
Typical memory while developing~50 MB100s of MB (containers)GBs (Docker image)
Data persists across restarts free, defaultn/apaid tier

swipe the table to compare →

Honesty by design. pulse does one workflow completely — CRUD APIs with background jobs. Anything outside that subset fails loudly with a message saying so, never silently wrong. S3, SNS, EventBridge and Step Functions are on the roadmap, not pretended.

05 build

Grow your app one command at a time

Every piece — a function, a route, a queue, a table — is one command. Run it bare and it asks instead of demanding flags; each edits pulse.yaml for you and applies live.

$ pulse add function notifier

Add a function

Writes services/notifier/handler.py — a working, commented Lambda handler — and registers it.

$ pulse add route POST /notify --function notifier

Give it a URL

Functions and routes stay separate on purpose — exactly how real AWS models them.

$ pulse add queue emails --worker send-email --dlq

Add a queue & worker

Queue, worker function, wiring and dead-letter queue in one line. Then pulse send emails '{…}'.

$ pulse add table customers --pk email

Add a table

A table's whole schema is its key — every other field is just code. No migrations, ever.

pulse remove is the exact inverse — it unwires the piece and never deletes your code or data.

Or start from a template

Four starters, each adding exactly one concept. All ship in Python and Node, use the plain AWS SDK, and run unchanged in real AWS.

$ pulse init --list
hello

One function behind GET /hello — the smallest possible start.

your first function

todo-api

Real CRUD on one DynamoDB table: create, list, complete, delete.

+ a real table

webhook-relay

Ack-fast webhook handling with retries and a dead-letter queue.

+ a queue & DLQ

api-and-worker ★

The full loop: API + queue + worker + table, wired and narrated.

everything together

06 faq

Questions people actually ask

Can I really run AWS Lambda locally?

Yes. pulse runs your functions natively against the real Lambda Runtime API — the same contract AWS uses in production. Node.js and Python, no Docker, ready in about 100 milliseconds.

Does pulse require Docker?

No. pulse is one ~20 MB binary that runs your functions as native processes — no images to pull, no containers to boot, no daemon idling in the background. A complete app with an API, a queue, a worker and a table sits around 50 MB of memory, which is why it starts in milliseconds instead of tens of seconds.

Which languages does pulse support?

Node.js and Python today. Every template ships in both, and handlers are plain AWS SDK code with no pulse imports to remove later. The other Lambda runtimes — Java, Go, .NET, Ruby — are not supported yet, and pulse says so plainly rather than half-running them.

Is pulse a LocalStack alternative?

For the inner development loop, yes. LocalStack emulates ~100 AWS services inside Docker and shines at testing infrastructure code. pulse does one workflow completely — Lambda, HTTP, SQS, DynamoDB — natively, with dev-server ergonomics: hot reload, event replay, a live monitor.

Does pulse replace sam local?

They do different jobs. sam local starts a container per invocation and cannot run the queue → worker → dead-letter-queue loop continuously; pulse runs your whole app as a long-lived local cloud with hot reload. Your deploy pipeline keeps using SAM or CDK — pulse is development-time only and never touches it.

Does it work with boto3 and the AWS SDK?

Yes — plain boto3 in Python, AWS SDK for JavaScript v3 in Node. pulse sets AWS_ENDPOINT_URL for your functions automatically, so the same code talks to pulse locally and to real AWS in production.

Does my data survive restarts?

Yes. DynamoDB items, queued messages and event history persist in .pulse/data (SQLite). Stop the engine, restart tomorrow — everything is still there, free, by default.

How do I deploy an app built with pulse?

With whatever you already use — SAM, CDK or the Serverless Framework. pulse is development-time only and your code is vanilla AWS SDK throughout, so there is nothing to strip out.

Ready for the instant dev loop?

Install pulse with one command and boot your first Lambda in under 100 milliseconds.

macOS · recommended
$brew install --cask geetnsh2k1/pulse/pulse

then run pulse tour — five minutes, hands-on, nothing simulated