@aws-blocks/blocks
v0.6.0
Published
**Write your backend and frontend together — fully typed, runnable on your laptop, deployable to AWS unchanged.**
Downloads
22,892
Maintainers
Readme
AWS Blocks
Write your backend and frontend together — fully typed, runnable on your laptop, deployable to AWS unchanged.
AWS Blocks is a backend framework built from Building Blocks: self-contained modules that each bundle a CDK construct, its AWS SDK integration, and a local mock. You compose blocks in one directory, export an API, and call it from your frontend with end-to-end type safety. No client generation, no glue code, no AWS account needed to start.
This package (@aws-blocks/blocks) re-exports every Building Block and the core primitives, so you import everything from one place:
import { Scope, ApiNamespace, KVStore, AuthBasic } from '@aws-blocks/blocks';- Type-safe, end to end — your frontend calls backend methods directly; types flow through automatically.
- Local-first — every block runs as an in-memory mock, so you build and test with zero cloud setup.
- Deploys unchanged —
npm run sandboxswaps the mocks for real AWS services (DynamoDB, Aurora, S3, Lambda…). Same code. - Low ceremony, high ceiling — common things are one line; when you need the underlying CDK construct or AWS SDK, it's right there.
Quick Start
npx @aws-blocks/create-blocks-app my-app
cd my-app
npm run dev # → http://localhost:3000 (mocks, no AWS account needed)--template <name> picks a starter (react, nextjs, backend, …); see @aws-blocks/create-blocks-app.
How it works
Your entire backend lives in one directory, aws-blocks/. You create blocks, then expose methods through an ApiNamespace:
// aws-blocks/index.ts
import { Scope, ApiNamespace, KVStore } from '@aws-blocks/blocks';
const scope = new Scope('my-app');
const store = new KVStore(scope, 'cache');
export const api = new ApiNamespace(scope, 'api', (context) => ({
async getValue(key: string) {
return await store.get(key);
},
async setValue(key: string, value: string) {
await store.put(key, value);
},
}));The frontend imports that API and calls it like a local function — fully typed, no fetch, no client codegen:
// src/
import { api } from 'aws-blocks';
await api.setValue('greeting', 'hello');
const value = await api.getValue('greeting'); // typed: string | nullThat's the whole model: define blocks → export an API → import it on the frontend. The transport (JSON-RPC over a single endpoint) is handled for you and is intentionally invisible.
Adding auth and data
Blocks compose. Here's the same API gated behind authentication and backed by a queryable table:
// aws-blocks/index.ts
import { Scope, ApiNamespace, AuthBasic, DistributedTable } from '@aws-blocks/blocks';
import { z } from 'zod';
const scope = new Scope('my-app');
const auth = new AuthBasic(scope, 'auth', { passwordPolicy: { minLength: 8 } });
const notes = new DistributedTable(scope, 'notes', {
schema: z.object({ userId: z.string(), noteId: z.string(), text: z.string() }),
key: { partitionKey: 'userId', sortKey: 'noteId' },
});
// Sign-up / sign-in endpoints, ready to wire to the frontend
export const authApi = auth.createApi();
export const api = new ApiNamespace(scope, 'api', (context) => ({
async addNote(text: string) {
const user = await auth.requireAuth(context); // 401s if not signed in
const noteId = crypto.randomUUID();
await notes.put({ userId: user.username, noteId, text });
return { noteId };
},
async listNotes() {
const user = await auth.requireAuth(context);
return await Array.fromAsync(notes.query({ where: { userId: { equals: user.username } } }));
},
}));Security: every
ApiNamespacemethod is a public internet endpoint with no auth by default. Gate a method by callingauth.requireAuth(context)(orauth.requireRole(...)) at the top. The local mock enforces nothing either — an ungated method passes every local check and still ships callable by anyone.
On the frontend, @aws-blocks/blocks/ui gives you provider-agnostic auth components, or drive authApi yourself:
import { Authenticator, onAuthChange } from '@aws-blocks/blocks/ui';
import { authApi, api } from 'aws-blocks';
document.body.append(Authenticator(authApi));
onAuthChange(authApi, (user) => {
if (user) api.listNotes().then(render);
});Building Blocks
Start from what you need:
- Store data
- Simple key → value (caches, flags, user prefs) →
KVStore(bb-kv-store) - Structured records with indexes and queries →
DistributedTable(bb-distributed-table) — default for most data - Relational / SQL (joins, transactions) → see Choosing a data block below
- Files, blobs, uploads, static assets →
FileBucket(bb-file-bucket) - A single config value or secret →
AppSetting(bb-app-setting)
- Simple key → value (caches, flags, user prefs) →
- Authenticate users
- Username/password, prototypes/MVPs →
AuthBasic(bb-auth-basic) - Cognito user pools, MFA, groups →
AuthCognito(bb-auth-cognito) - External identity provider (OIDC) →
AuthOIDC(bb-auth-oidc)
- Username/password, prototypes/MVPs →
- Run work outside the request/response
- Fire-and-forget background jobs →
AsyncJob(bb-async-job) - Scheduled / recurring tasks →
CronJob(bb-cron-job)
- Fire-and-forget background jobs →
- Push live updates to browsers (chat, presence, dashboards) →
Realtime(bb-realtime) - Build AI features
- Agent with tool use + conversation →
Agent(bb-agent) - Semantic document retrieval (RAG) →
KnowledgeBase(bb-knowledge-base)
- Agent with tool use + conversation →
- Send transactional email →
EmailClient(bb-email-client) - Serve a raw HTTP endpoint (webhook receiver, health check, redirect, non-JSON response) →
RawRoute(core); everything else goes throughApiNamespaceRPC - Observe and operate
- Structured logs →
Logger(bb-logger) - Custom metrics →
Metrics(bb-metrics) - Distributed traces →
Tracer(bb-tracer) - Auto CloudWatch dashboard →
Dashboard(bb-dashboard)
- Structured logs →
Choosing a data block
Default to DistributedTable for your data models unless your domain specifically requires SQL engine capabilities.
Reach for one of the SQL blocks when you need to filter or join results across more than one related record, filter models on many dimensions with no preset hierarchy, store large objects, require transactions, or otherwise need the flexibility or familiarity of SQL that NoSQL does not offer.
If you need SQL, prefer DistributedDatabase for basic Postgres-compatible querying. Use Database specifically when you need a full (more expensive) Postgres implementation where the engine itself provides and enforces foreign keys, row level security, triggers, views, large transactions (more than 3,000 rows), or integration with an existing Postgres database. Note it carries an idle cost at minimum 0.5 ACU, or a cold start when scaling from zero, unlike the other two blocks.
Building Block documentation
Every Building Block ships its docs inside the @aws-blocks/blocks package under docs/<block>/: each docs/<block>/ folder contains that block's README.md, plus API.md, DESIGN.md, and CHANGELOG.md where present. To read them, locate the bundled folder:
node -p "require('path').dirname(require.resolve('@aws-blocks/blocks/docs/README.md'))"If resolution fails, fall back to node_modules/@aws-blocks/blocks/docs. That folder holds this guide (README.md), the framework's own API.md, TROUBLESHOOTING.md, and CHANGELOG.md (version history — read when troubleshooting), plus one subfolder per block; the catalog below lists every block.
| Block | What it does | Keywords |
|-------|--------------|----------|
| auth-common | Shared interfaces and UI components for all AWS Blocks auth Building Blocks. | — |
| bb-agent | AI agent with streaming, tool calling, and conversation persistence. | — |
| bb-app-setting | A single application configuration value backed by SSM Parameter Store. | — |
| bb-async-job | Background job processing backed by SQS and Lambda. | queue, job, background, async, worker, submit, batch, retry, status, transitions, SQS |
| bb-auth-basic | Simple username/password authentication with JWT sessions, password policy, and optional code-confirmed signup and password reset. | — |
| bb-auth-cognito | Authentication backed by Amazon Cognito User Pools. | — |
| bb-auth-oidc | OIDC sign-in gate for AWS Blocks applications. | — |
| bb-cron-job | Scheduled task execution backed by EventBridge Scheduler and Lambda. | cron, schedule, timer, periodic, recurring, rate, EventBridge, background, interval |
| bb-dashboard | Auto-generated CloudWatch Dashboard for application observability. | — |
| bb-data | Full PostgreSQL database — provisions Aurora Serverless v2 by default, or connects to an existing PostgreSQL database (Supabase, Neon, etc.) via fromExisting(). | — |
| bb-distributed-data | Serverless SQL database backed by Amazon Aurora DSQL. | — |
| bb-distributed-table | Structured data storage backed by DynamoDB with secondary indexes and rich query capabilities. | — |
| bb-email-client | Transactional email sending via Amazon SES. | — |
| bb-file-bucket | File storage backed by Amazon S3. | — |
| bb-knowledge-base | Semantic document retrieval backed by Amazon Bedrock Knowledge Bases. | — |
| bb-kv-store | Simple key-value storage backed by DynamoDB. | — |
| bb-logger | Structured logging with consistent JSON format, log levels, and contextual metadata. | — |
| bb-metrics | Custom application metrics backed by Amazon CloudWatch (via Embedded Metric Format). | — |
| bb-realtime | Real-time pub/sub messaging backed by API Gateway WebSocket + DynamoDB. | — |
| bb-tracer | Distributed tracing backed by AWS X-Ray. | — |
| core | Core primitives for building full-stack applications with the AWS Blocks. | — |
| hosting | Low-level CDK L3 constructs for deploying web applications on AWS | — |
| pipeline | CDK Pipelines-based CI/CD construct for AWS Blocks applications. | — |
Local development and deploying
| | npm run dev | npm run sandbox |
|---|---|---|
| Blocks run as | in-memory mocks | real AWS services |
| AWS account | not needed | required |
| Data | persists to .bb-data/ (delete to reset) | lives in AWS |
| Use for | rapid iteration, tests | pre-production validation against real services |
Deploying needs AWS credentials.
npm run devis fully local (no creds).npm run sandboxandnpm run deployprovision real AWS resources, so configure credentials first — e.g.aws configure sso+aws sso login, oraws configure(verify withaws sts get-caller-identity). Use least-privilege credentials scoped to the services your blocks deploy — not broadAdministratoraccess.
npm run deploy does a full production deploy; npm run sandbox:destroy tears the sandbox down. The same backend code runs in all three — blocks switch implementations automatically.
npm run deploy streams CloudFormation events to stdout as they happen, so npm run deploy | tee deploy.log shows live progress instead of going silent for minutes, and a deploy failure keeps its reason on stderr (that stays the place to grep for why a deploy failed). On POSIX the deploy also survives a stray reap: a single SIGTERM, or any SIGHUP — a closed terminal, a backgrounded npm run deploy & — logs a line and keeps streaming rather than abandoning a stack update CloudFormation is still applying. Press Ctrl-C, or send SIGTERM twice, to stop it. That signal resilience is POSIX-only: Windows has no process groups and no OS-delivered SIGTERM/SIGHUP, so there a kill on the process tree still ends the deploy.
Testing
The fastest loop is calling your API through its typed import in test/e2e.test.ts — no browser, no mocking:
import { test } from 'node:test';
import assert from 'node:assert';
import type { api as ApiType } from 'aws-blocks';
let api: typeof ApiType;
test.before(async () => { api = (await import('aws-blocks')).api; });
test('stores and reads back a value', async () => {
await api.setValue('k', 'v');
assert.equal(await api.getValue('k'), 'v');
});Run with npm run test:e2e. Write the test first, iterate against mocks until it passes.
Best practices
- Export every API — the frontend can only import what you
exportfromaws-blocks/index.ts. - Validate with schemas — pass a Zod/Valibot schema to data blocks for compile-time and runtime type safety.
- Don't block the request — use
AsyncJobfor anything slow;submit()returns ajobIdimmediately. - Guard against races — use conditional writes (
ifNotExists,ifValueEquals,ifFieldEquals) instead of read-modify-write. - Test locally first — mocks behave like the real service; deploy once it's green.
Common mistakes
- Ungated endpoints — methods are public unless you call
requireAuth/requireRole. The local mock won't catch this for you. - Forgetting to export — an
ApiNamespaceyou don't export is invisible to the frontend. DatabasewhenDistributedTablewould do — Aurora costs more and has cold starts; reach for SQL only when you need it.- Curling REST-style paths — there is no
GET /api/getData. All calls are JSON-RPC to a singlePOST /aws-blocks/api; use the typed import instead.
Security Considerations
- Use
await auth.requireAuth(context)in every method that shouldn't be public — ApiNamespace methods are unauthenticated by default - Use
new AppSetting(scope, id, { secret: true })for API keys and credentials — never hardcode or use.envfiles - Always attach a schema to KVStore/AppSetting that accepts user data — the RPC layer validates structure but not business logic
- Do not add broad
*IAM policies — each Building Block already grants least-privilege scoped to its own resources - Never change
blockPublicAccesson FileBucket — serve public files through CloudFront instead - Configure
CORS_ALLOWED_ORIGINSexplicitly for production — avoid wildcards - For cross-domain deployments, pass
crossDomain: trueto auth constructors (enablesSameSite=None; Secure; Partitioned) - Enable
monitoring: { enabled: true, snsTopicArn: '...' }on Hosting for production alerts - Add WAF and API Gateway throttling via CDK for public-facing apps — not included by default
- Logger provides serialization safety (circular refs, type coercion) but does NOT redact sensitive content — never pass raw credentials, tokens, or secrets to Logger methods; sanitize context objects before logging
VPC Support
AWS Blocks supports running your backend in a VPC for network-level isolation or to connect to VPC-bound resources. You can let Blocks manage endpoint provisioning and security groups automatically, or bring a fully-configured VPC and handle networking yourself.
See VPC.md for usage, configuration options, cost details, and guidance on when a VPC is appropriate.
Reference
- Per-block documentation:
docs/<block>/README.md(overview), plusdocs/<block>/API.md(full API reference) anddocs/<block>/DESIGN.md(architecture & rationale) where present — e.g.docs/bb-distributed-table/README.md. The catalog + decision tree live indocs/README.md. - UI components (
@aws-blocks/blocks/ui):Authenticator,AuthenticatedContent,AccountMenuBar,onAuthChange,broadcastAuthChange— framework-agnostic, return DOM nodes. See the@aws-blocks/auth-commonREADME. - SSR (
@aws-blocks/blocks/server):withAuthforwards browser cookies to API calls during server rendering. See the@aws-blocks/coreREADME. - Wire protocol & debugging: the client is JSON-RPC 2.0 over a single endpoint — you should never call it directly. For
curl-level troubleshooting, see TROUBLESHOOTING.md.
