Hello Devs,
For the past few weeks I have been digging into AWS Blocks. I learned so much that I wanted to share an honest review of the product from my point of view.
For this purpose I dove deep into its capabilities, custom blocks, where it works and where it breaks. Because knowing where something breaks is as valuable as knowing what it does. It tells you whether to adopt it, when to stop, and what to watch out for before you are already in production.
Note: AWS Blocks is currently in Preview. The GitHub repository shows v0.2.3 with approximately 2.7k downloads per week. Preview means APIs can change, behaviours can shift, and you are an early evaluator, not a stable-release user. Keep that in mind as you read. Many issues might get resolve after GA.
What AWS Blocks Is — The Real Mechanism
The official description: "Each Block bundles your application code, a local development setup, and the infrastructure to run it."
What that actually means under the hood: AWS Blocks uses Node.js conditional exports to load a completely different implementation of the same code depending on where it runs.
// From each Block's package.json
"exports": {
".": {
"blocks-local": "./dist/local.js",
"blocks-cdk": "./dist/cdk.js",
"blocks-runtime": "./dist/runtime.js",
"default": "./dist/index.js"
}
}
When you run npm run dev — it loads local.js. In-memory, filesystem, no network.
When you run cdk synth — it loads cdk.js. Produces CloudFormation constructs.
When your Lambda runs in production — it loads runtime.js. Real AWS SDK calls.
Same line of code. Three execution paths. No code changes needed.
One thing to be aware of: if you use a custom bundler like Vite or Jest with a non-standard configuration that does not pass these custom Node.js conditions correctly, the wrong implementation could load silently. AWS is aware of this and ships a consistency checker in the root package.json specifically for this scenario::
"check:exports-consistency": "npx tsx scripts/check-aws-blocks-exports-consistency.ts"
If your build tool — Vite, Jest, a custom bundler — does not pass these custom Node.js conditions correctly, the wrong implementation loads silently. No error. Your Lambda could run the local in-memory mock in production. AWS built a validation script because this is a real failure mode, not a hypothetical one.
Where Local Dev Works Great
Let me give you a concrete situation from my own team.
Our RDS and DynamoDB tables are inside a private VPC. No public endpoint. Corporate laptops have no AWS CLI credentials. So the developer workflow today looks like this:
Write code locally, push manually to an EC2 instance that has an IAM role, test there, find a bug, repeat.
Every iteration goes through EC2. The inner loop is slow not because the code is complex, but because you cannot connect to your data layer from your laptop at all.
Here is how the two workflows compare:
AWS Blocks changes this. KVStore and DistributedTable locally run in-memory via local mock implementations. No credentials needed. No VPC. No network call. A developer on a locked-down corporate laptop can build and test application logic without touching AWS.
When they push to sandbox, same code, no changes, it picks up the IAM role from the EC2 instance automatically.
The improvement is real. EC2 stops being "where I test my code" and becomes "where I run sandbox deploys." That is a narrower use of it, but a better one.
Where this help ends: Application logic only. If your DynamoDB query behaviour, your Bedrock responses, or your RDS schema need to be tested, you still need the sandbox. Blocks improves the iteration speed on logic, not on integration.
The Database Block — A Postgres Build With Real Limits
The Database Block offers type-safe Postgres that runs locally without Docker or any installation.
What actually runs locally is PGlite — PostgreSQL compiled to WebAssembly. Not a real Postgres process. A single-process, single-user WASM build from the v0.2.x/v0.3.x lineage.
The limitations matter for modern product use cases:
pgvector— the extension used for vector similarity search in AI applications — requires a native WASM build that is not includedPostGIS has the same problem
Advanced index types, PL/v8, PL/Python, and compiled C extensions are not supported in the WASM sandbox
So if your product stores embeddings and runs similarity queries against them locally, PGlite will not support it. You will build locally, things will look fine, you will deploy to sandbox, and Aurora will behave differently from PGlite. You find the gap at sandbox time, not local time.
To be specific: this is not about all AI use cases. If you are using Bedrock for generation or using an Agent Block, PGlite is fine. The limitation is specifically when your database layer itself needs to handle vector operations, like storing and querying embeddings for semantic search.
AsyncJob and CronJob — The Gap Between Local and Production
This is the part I have not seen written about anywhere.
Locally, both AsyncJob and CronJob share the same Node.js event loop as your local web server. The AsyncJob local implementation uses an in-memory array and polls it every 100ms:
// packages/bb-async-job/src/local.ts
const queue: Task[] = [];
setInterval(async () => {
if (queue.length === 0) return;
const task = queue.shift();
if (task) {
await handler(task.payload, task.context);
}
}, 100);
There is no backpressure. No cap on queue size. Say your frontend pushes a large volume of tasks — the array grows unchecked in the V8 heap until the process runs out of memory and crashes. And it takes your local web server down with it, because they share the same process.
For CronJob — the local implementation hooks into standard Node.js timers. Say you have a cleanup cron that fires every minute and scans a large mock table. It blocks the single-threaded event loop while it runs. Your API endpoints start timing out. You spend time debugging your API route when the real problem is your background cron running on the same thread.
In production, these are completely different:
AsyncJob → SQS + isolated Lambda
CronJob → EventBridge + isolated Lambda
Fully separate compute. Independently scaled. The production architecture has no shared event loop at all.
Local behaviour and production behaviour are architecturally different — not just scaled differently. Testing async workloads locally tells you very little about what will happen under production load patterns.
AWS Blocks Was Built with AI Agents as the Primary User
Something I found in the root package.json that is not in any documentation:
"scripts": {
"monte-carlo": "tsx scripts/monte-carlo.ts",
"monte-carlo:cached": "tsx scripts/monte-carlo.ts --cached"
}
There is also a scripts/agent-bench folder in the repository.
AWS is running Monte Carlo simulations to benchmark how reliably an AI coding agent produces correct Blocks code. The steering files shipped inside every Block package are not just a developer convenience — they are instructions specifically for AI agents on how to generate correct AWS architecture.
The "no infrastructure knowledge needed" pitch makes more sense when you read it this way. Blocks constrains the solution space so an AI agent cannot accidentally misconfigure IAM, create a public resource, or mix up local and production implementations. The simplicity is by design — for the agent generating the code, not just for the human reading it.
This is where Blocks has the strongest case. If your workflow is "I describe what I want to an AI coding assistant and it generates my backend" — Blocks gives the agent guardrails that plain CDK or raw AWS SDK does not.
Mobile Clients — One Manual Step That Will Cause You Problems
The blocks.spec.json file is what drives type-safe client generation for Swift, Kotlin, and Dart/Flutter apps. It is not automatically regenerated on every save. You run it explicitly:
npx blocks-generate-spec
The spec is a static file committed to your repository. Native mobile build tools read it to generate typed clients.
Say your developer renames updateTask(id: string) to updateTask(id: string, patches: PatchObject) and pushes without regenerating the spec. The mobile team pulls the branch. Their Kotlin or Swift client builds cleanly — no compiler error. The app works fine in their local tests. When the app hits the real API in sandbox, it throws JSON-RPC validation errors at runtime because the client is sending the old payload shape.
This gap does not exist in pure TypeScript web apps. It only surfaces in projects with native mobile clients. If your product has a mobile app and a separate team touching the backend, you need spec regeneration wired into your pre-commit hooks or CI pipeline — otherwise this will happen.
What Enterprise Teams Should Know Before Adopting
A few things I found in the repository worth knowing before you recommend this to your team.
Node.js 22 is a hard requirement. The repository enforces it. Not a soft recommendation. If your team is on Node 18 or Node 20 LTS — and many enterprise teams are — you need to upgrade before Blocks will even install cleanly.
CDK is pinned to an exact version. From the root package.json:
"aws-cdk-lib": "2.257.0"
Not ^2.257.0. If your enterprise monorepo already has other CDK applications at a different version, you have a dependency conflict on day one.
Telemetry is enabled by default. At startup, Blocks notifies you that anonymous usage data will be collected. You can disable it:
AWS_BLOCKS_DISABLE_TELEMETRY=1
If your team is on a corporate network that goes through security review for any new tooling, this needs to be declared upfront.
The Database Block uses Kysely as its SQL query builder. Kysely is a type-safe SQL query builder for TypeScript think of it like a lightweight alternative to Prisma, where you write SQL-shaped queries in TypeScript and get full type safety without a heavy ORM layer. It is a good tool. But it is not Prisma, not TypeORM, and it is not prominently mentioned in the docs. If your team already uses Prisma across your other services, you will have two different SQL paradigms in one codebase. Worth knowing before you start.
First deploy is not lightweight. Based on hands-on testing of the default template (AuthBasic + DistributedTable + Realtime), the first sandbox deploy creates 82 CloudFormation resources and takes approximately 150 seconds. Source: dev.classmethod.jp/en/articles/20260620-aws-blocks-preview. Before recommending adoption, understand what your AWS bill baseline looks like even at idle.
Where It Fits — What I Actually Think
After spending a few weeks on this, here is where I landed.
It genuinely helps:
Greenfield internal tools or MVPs - not migrating existing systems
Teams where an AI coding agent is the primary backend developer
Developers blocked by credentials, VPC access, or local environment setup — Blocks gives them a fast inner loop with zero infrastructure dependency
Small teams on AWS who want to ship something in a day without writing CloudFormation or setting up IAM from scratch
It will cause problems:
If background jobs or scheduled tasks are core to your product what you test locally is architecturally different from production
If your product has a native mobile app and a backend team that moves independently the spec sync gap will hit you
If your database needs pgvector or PostGIS locally local fidelity breaks before you can validate the feature
If your enterprise monorepo is already on a specific CDK version dependency conflict on day one
The honest limit: The Block catalogue covers the common cases well. The moment you need something outside it — an SQS queue, a Slack webhook, a custom rate limiter — you write CDK. The repo even includes a custom bb-queue Block as an example in test-apps/extending-blocks-guide/packages/bb-queue to show you how. That escape hatch works. But it means you are now maintaining a custom Block alongside your application code, which adds overhead the "zero infrastructure knowledge" pitch does not account for.
Spending a few weeks on this gave me a clearer answer than I expected. There is a real use case for Blocks and it is real. For a developer blocked by infrastructure friction, or for an AI agent generating an AWS backend from a prompt, Blocks is a meaningful improvement over starting from scratch.
For anything that touches async workloads, mobile clients, or AI-adjacent database features go in with your eyes open.
Feel free to reach out to me on Twitter at @avinashdalvi_ or comment below.
References :
AWS Blocks repository — github.com/aws-devtools-labs/aws-blocks
AWS Blocks Developer Guide — docs.aws.amazon.com/blocks/latest/devguide


Top comments (0)