Lambda Web Functions After a Hono Lambdalith: What Changes
Lambda Web Functions run a Hono app as a plain HTTP server. What moves off API Gateway, what stays in the app, and when a Hono Lambdalith is still the better fit.
Lambda Web Functions, announced on 12 October 2026, run a Node.js app that listens on a port as a Lambda resource. Each one gets its own HTTPS endpoint, serves many concurrent requests per execution environment, and scales to zero. A Hono app ports to them with few router changes, but the hosting contract around it does not. The @hono/aws-lambda adapter, every read of c.env.event, the gateway’s per-route authorizers and throttles, and per-function knobs such as provisioned concurrency have no direct equivalent. For a Hono Lambdalith that already runs well behind API Gateway, the recommendation is to keep it there and make the app host-agnostic now. Move a bounded context to a Web Function only when a named trigger applies: long requests, streaming, I/O-heavy handlers, server-side rendering, or multi-Region latency.
The starting point is the orders API from Single-Purpose Lambdas to a Hono Lambdalith, Route by Route. The feature is one day old, and no proof of concept has run against it yet. Every Web Functions fact below comes from AWS documentation published at launch, and the code follows the shape AWS documents.
Web Functions in the Terms of a Lambdalith#
AWS now describes three Lambda form factors: Event Functions (the classic event-driven model), Web Functions, and MicroVMs. A Web Function contains immutable revisions (code plus configuration) and up to ten endpoints. An endpoint owns an HTTPS domain, an auth type, scaling and throttle settings, and revision weights that route traffic to one or two active revisions. Endpoint types are HomeRegion, MultiRegion (one global domain with best-effort latency routing), and PerRegion (one domain per Region).
The constraints that decide whether a Lambdalith can move are narrow and concrete, according to the runtimes (opens in new tab), core concepts (opens in new tab), and HTTP (opens in new tab) pages:
- Runtime
nodejs24.xonly, Arm64 only, a fixed 2 vCPUs and 2 GB of memory per environment, a default V8 heap of 1,024 MB, and 512 MB of shared/tmp. - The server must listen on the host and port in
AWS_LAMBDA_HTTP_ENDPOINTwithin 10 seconds. The entry file isindex.jsat the package root unlessAWS_LAMBDA_NODEJS_ENTRYPOINTsays otherwise;package.jsonmainis not read. maxConcurrencyPerEnvironmentranges from 1 to 128 with a default of 64. It is an upper bound on a limit Lambda manages dynamically, so sustained concurrency per environment is often lower.- The request timeout ranges from 3 to 900 seconds, with a default of 30.
- HTTP/1.1 only, a 128 KiB limit on the request head, no WebSocket upgrades, and a half-duplex request path: the app reads the whole request body before it writes the response.
- Code deploys from a .zip in a versioned S3 bucket, up to 512 MB unzipped. A new revision does not inherit settings from the previous one.
- Launch Regions are US East (N. Virginia), US East (Ohio), US West (Oregon), Asia Pacific (Tokyo), and Europe (Ireland), per the launch post (opens in new tab).
Billing follows a different shape from Event Functions: requests, active CPU time, memory over the environment’s lifetime, and data transfer. The pricing page (opens in new tab) has the current rates.
The Same Hono App Behind a Different Entry File#
The developer guide (opens in new tab) says frameworks such as Hono run “with no Lambda-specific adapters or wrappers”. That holds for the router and does not hold for the edges. In the previous post, src/orders/app.ts, the sub-apps, the Zod validators, and the app.request() tests are portable. The handler file, the Env bindings, the scope middleware, and the observability middleware are not.
AWS’s own Hono sample on the samples page (opens in new tab) uses @hono/node-server. The Lambdalith’s handler.ts becomes a server entry that binds the address Lambda provides:
// src/orders/server.ts (bundled to index.js at the package root)
import { serve } from '@hono/node-server'
import { app } from './app'
// Lambda sets AWS_LAMBDA_HTTP_ENDPOINT as "host:port". The fallback is for local runs only.
const [host, port] = (process.env.AWS_LAMBDA_HTTP_ENDPOINT ?? 'localhost:3000').split(':')
serve({ fetch: app.fetch, hostname: host, port: Number(port) })
process.on('SIGTERM', () => {
// Lambda allows at most 1 second here; flush anything buffered, then exit.
process.exit(0)
})
The Env type loses its Lambda bindings. { event, lambdaContext } does not exist under @hono/node-server, so anything that read c.env.event or c.env.lambdaContext needs a new source. Request correlation comes from the lambda-web-request-id header that Lambda adds to each request. Values the app produces itself, such as the verified token payload, go into Hono’s context variables.
// src/orders/env.ts
export type Env = {
Variables: { jwtPayload?: Record<string, unknown> }
}
JWT validation moves into the app when no gateway authorizer sits in front. Hono’s built-in JWK middleware (opens in new tab) verifies the bearer token against the issuer’s key set; its alg option is required and lists the accepted algorithms. The scope check from the previous post keeps its core insight (read the token’s scope or scp claim) and only changes where it reads the claims from.
// src/orders/auth.ts
import { createMiddleware } from 'hono/factory'
import { jwk } from 'hono/jwk'
import type { Env } from './env'
const issuer = process.env.JWT_ISSUER ?? ''
// Verifies signature, exp, nbf, iat, and iss; the payload lands in c.get('jwtPayload').
export const verifyJwt = jwk({
jwks_uri: `${issuer}/.well-known/jwks.json`,
alg: ['RS256'],
verification: { iss: issuer },
})
export const requireScope = (scope: string) =>
createMiddleware<Env>(async (c, next) => {
const claims = c.get('jwtPayload') ?? {}
const raw = claims.scope ?? claims.scp ?? ''
const granted = Array.isArray(raw) ? raw : String(raw).split(' ')
if (!granted.includes(scope)) {
return c.json({ message: 'Forbidden' }, 403)
}
await next()
})
CORS moves fully into the app as well, because Lambda adds no CORS headers. hono/cors becomes the only CORS layer, and the previous post’s pitfall about gateway CORS conflicting with integration CORS disappears.
Per-route metrics stay necessary, and they need a rewrite. The EMF page (opens in new tab) states that EMF objects must go to standard output with process.stdout.write, because Lambda wraps console output in its own JSON log event and CloudWatch does not extract metrics from the wrapped object. Built-in metrics also carry no revision dimension, so a canary needs the version in the app’s own metrics. Building the object inside the request avoids a buffer shared between concurrent requests:
// src/orders/observe.ts
import { createMiddleware } from 'hono/factory'
import { routePath } from 'hono/route'
import type { Env } from './env'
const version = process.env.APP_VERSION ?? 'unknown'
export const observe = createMiddleware<Env>(async (c, next) => {
const start = performance.now()
await next()
const route = `${c.req.method} ${routePath(c, -1)}`
// One object per request: nothing is shared between requests in flight.
process.stdout.write(
JSON.stringify({
_aws: {
Timestamp: Date.now(),
CloudWatchMetrics: [
{
Namespace: 'orders',
Dimensions: [['route', 'version']],
Metrics: [
{ Name: 'requests', Unit: 'Count' },
{ Name: 'faults', Unit: 'Count' },
{ Name: 'latency', Unit: 'Milliseconds' },
],
},
],
},
route,
version,
requests: 1,
faults: c.res.status >= 500 ? 1 : 0,
latency: performance.now() - start,
status: c.res.status,
requestId: c.req.header('lambda-web-request-id'),
}) + '\n',
)
})
The request ID stays a plain field so it is searchable in Logs Insights without creating a metric per request. The Powertools Logger and Metrics from the previous post are not mentioned in the Web Functions docs. Before reusing them, check two things: whether Metrics writes to stdout directly or through console, and whether their module-level instances behave correctly with concurrent requests in one process.
Static assets can be served from the function with serveStatic, as AWS’s sample does. When CloudFront is the front door, serving them from S3 through CloudFront keeps that traffic off the function.
The Hosting Contract, Row by Row#
The table below maps each concern from the previous post to its Web Function counterpart. The API Gateway column is the HTTP API setup from that post.
| Concern | Hono Lambdalith behind API Gateway | Hono on a Web Function |
|---|---|---|
Router, routes, Zod validation, app.request() tests | Hono | Unchanged |
| Adapter | handle() from @hono/aws-lambda | serve() from @hono/node-server on AWS_LAMBDA_HTTP_ENDPOINT |
| Requests per environment | One at a time | Up to maxConcurrencyPerEnvironment (default 64, max 128); the dynamic limit may be lower |
| JWT validation and scopes | Gateway JWT authorizer per route | In the app, or on a front door you keep |
| Per-route throttling | Route settings or usage plans | None per route; endpoint rateLimit and maxEnvironments, per Region |
| Request validation | Hono (or REST validators) | Hono only |
| Request timeout | 29 s default on HttpLambdaIntegration | 3 to 900 s, default 30 s |
| Canary | Weighted alias; no canary on HTTP API | Revision weights on the endpoint, two revisions |
| Warm capacity | Reserved and provisioned concurrency | None; always scales from zero |
| Memory, CPU, architecture | 128 to 10,240 MB, x86 or Arm | Fixed 2 GB and 2 vCPU, Arm64 only |
| Runtimes | Every Lambda runtime | nodejs24.x only |
| Custom domain and WAF | API Gateway custom domain, WAF on REST | Only through a front door (CloudFront or API Gateway) |
| Private ingress | REST private APIs | Not available; the endpoint is internet-reachable |
| Streaming | Function URLs with streamHandle | Built in (SSE, chunked); no WebSocket |
| Built-in metrics | Per function, plus per route on the gateway | Per endpoint for requests, per function for environments; no route or revision dimension |
| Billing | Duration per invocation | Requests, active CPU, memory over environment lifetime, data transfer |
Most rows move a responsibility from configuration into code. Scope checks, CORS, and validation become middleware you test with app.request(). Throttling becomes an endpoint-wide setting, so a route that relied on its own throttle loses that isolation. The timeout row widens the window from under 30 seconds to up to 15 minutes, which is the main reason long-running routes are candidates. The capacity rows remove options: there is no provisioned floor, no memory dial, and no x86.
The concurrency row matters most. Everything in Code Architecture by Init Amortization about module-scope clients still holds. A database pool or SDK client created once per environment is still the right pattern. Module-scope mutable per-request state is the new hazard. On an Event Function a module-level let currentUser was wrong in style but safe in practice, because one environment served one request. On a Web Function the same variable is shared by every request in flight on that event loop, up to 64 by default. Per-request logger context appended to a singleton, caches mutated across an await, and metric buffers flushed at the end of a request all leak between requests in the same way. Hono’s c.set and c.get give each request its own scope.
CPU-bound work has the opposite problem. A long synchronous loop on an Event Function delayed one request; on a Web Function it delays every request in that environment. Move such work to worker_threads or lower maxConcurrencyPerEnvironment for the endpoint.
Choosing the Front Door#
The networking (opens in new tab) and endpoint access control (opens in new tab) pages describe the options. An endpoint uses one of two auth types: IamAuth (callers sign with SigV4 or SigV4a) or ApplicationManaged (the app decides). Either way, the endpoint domain stays reachable from the internet.
Direct endpoint with ApplicationManaged is the simplest shape. The app handles authentication, CORS, and abuse protection, and the endpoint domain is the public URL. There is no custom domain. It fits internal tools, preview environments, and machine-to-machine calls that carry app-verified tokens.
CloudFront with Origin Access Control in front of an IamAuth endpoint is the production shape AWS documents. The OAC uses origin type lambda and signing behavior always-amz-auth. A resource-based policy grants cloudfront.amazonaws.com the lambda:InvokeWebFunctionEndpoint action, scoped by aws:SourceArn. CloudFront signs each origin request. Lambda strips only Authorization values that are AWS signatures, so the viewer’s own bearer token can still reach the app for the JWK middleware. CloudFront drops Authorization on GET and HEAD unless the cache policy includes it, so add it to the cache policy (opens in new tab) on every behavior that uses this origin. Lambda@Edge origin-request and origin-response triggers are not supported on those behaviors. This shape adds a custom domain, WAF, caching, and HTTP/2 and HTTP/3 at the edge. The trade-off is a second resource to configure, plus one rule: CloudFront must not forward the viewer’s Host header. If it does, Lambda answers 404 Platform.InvalidEndpoint. For CloudFront as a front door in general, see Edge Computing on AWS.
API Gateway kept in front preserves gateway JWT authorizers, route throttles, and usage plans. AWS’s best-practices guidance (opens in new tab) lists it as a valid front door, but only CloudFront OAC is documented as signing for IamAuth. Behind any other front door the endpoint must be ApplicationManaged. Because the endpoint stays directly reachable, AWS’s guidance is to verify a shared secret or token in the application. The costs are a second hop, a secret to rotate, and the gateway’s integration timeout, which still caps request duration. No AWS page shows this exact pairing yet. Treat it as a migration bridge, and verify it (especially how the Host header reaches Lambda) before relying on it.
Moving a Bounded Context Without a Big-Bang Cutover#
The previous post’s discipline carries over: one small, reversible step at a time, with parity checked before each cutover. The unit of cutover changes from a function to a path on the front door. The decision for each route runs as follows, with staying on the Lambdalith as the root.
- Gate on the constraints first. Any route that needs reserved or provisioned concurrency, more than 2 GB, x86 native modules, a non-Node runtime, private ingress, usage-plan throttles, or a Region outside the launch list stays where it is. This is the counterpart of “Routes That Stay Single-Purpose” in the previous post.
- Make the app host-agnostic. Remove reads of
c.env.eventandc.env.lambdaContext, take the request ID from headers, and add the JWK middleware while the gateway authorizer still validates. The checks are redundant during this phase, and the Lambdalith keeps working with every one of these changes. They therefore ship before any infrastructure change, and they are worth doing even if the move never happens. - Audit for concurrency. Search for module-scope
let, caches mutated acrossawait, per-request context appended to singletons, and metric buffers. Then run concurrent requests against the server locally, as AWS’s testing guidance (opens in new tab) for Web Functions recommends. - Package for Arm64 and the entry contract. Bundle to
index.jsat the archive root, add"type": "module"to the packagedpackage.jsonfor ESM output, and build native dependencies forlinux/arm64. Upload to a versioned bucket and record the object version. - Stand up the Web Function next to the Lambdalith. CloudFormation has
AWS::Lambda::WebFunction,AWS::Lambda::WebFunctionRevision, andAWS::Lambda::WebFunctionEndpoint, and the CLI hasaws lambda-web deploy. There is no CDK L2 construct, so CDK users write them with the L1 classesCfnWebFunction,CfnWebFunctionRevision, andCfnWebFunctionEndpoint. Validate the revision on a test endpoint without production traffic, and run the previous post’s parity fixtures against it over HTTP. - Cut over per path at the front door. With API Gateway kept in front, retarget an explicit route’s integration from the Lambda integration to an HTTP integration that points at the endpoint. This is the same retarget-then-delete mechanic as before, with the same one-line revert. With CloudFront as the target, path-based cache behaviors can send
/orders/*to the Web Function origin while everything else keeps its current origin. In both cases, keep the Lambdalith deployed through a soak period. - Use revision weights for later deploys. For an endpoint created with the CLI, switch it to
autoDeploymentMode: Disabled. Template-created endpoints are driven byRevisionWeightsinstead. Then canary with two revisions, and attribute errors byAPP_VERSIONin the app’s own metrics. Keep the rollback revision referenced by an endpoint, because automatic cleanup deletes the oldest unreferenced revisions past 50.
The local run for step 3 uses the same command AWS documents, with a load tool to push concurrent requests through one process:
npx esbuild src/orders/server.ts --bundle --platform=node --format=esm --target=node24 --outfile=dist/index.js
echo '{"type":"module"}' > dist/package.json
cd dist && AWS_LAMBDA_HTTP_ENDPOINT=127.0.0.1:3000 node index.js &
sleep 2
npx autocannon -c 64 -d 10 http://127.0.0.1:3000/orders/123
A 64-connection run mirrors the default per-environment ceiling. A request-scoped bug shows up as responses carrying another request’s data, so assert on response bodies in a scripted test as well; a throughput number alone hides it.
The cost of this path is a phase where two hosting models run side by side, with two sets of dashboards and two deploy pipelines. What it buys is a per-path rollback that never depends on the new platform behaving well.
Endpoint Settings as the Remaining Throttle#
Without per-route throttles, three endpoint settings carry the protection role. The scaling page (opens in new tab) works through an example: maxEnvironments of 10 times maxConcurrencyPerEnvironment of 64 allows about 640 requests in flight. At 200 ms per request that is about 3,200 requests per second, bound by concurrency. At 10 ms per request, a rateLimit of 8,000 binds first.
rateLimit (0 to 10,000 RPS, in fixed steps: 0, 100 to 1,000 by 100, then 2,000 to 10,000 by 1,000) is the closest analogue to a gateway throttle and suits protecting a downstream database. maxEnvironments (2 to 10,000) caps how far the endpoint scales, and therefore spend. Both are enforced per Region, so a MultiRegion endpoint gets the limit in each Region it serves. When either limit fires, the 429 response carries a lambda-web-error-type header naming the cause. Setting rateLimit to 0 returns 503 Platform.EndpointDisabled, AWS documents that a value of 0 blocks all traffic, so it works as a kill switch. Per the quotas page (opens in new tab), account defaults per Region are 10,000 RPS per endpoint, 100,000 RPS per account, and 2,000 Arm64 vCPUs. New accounts start with lower Web Functions quotas that AWS raises automatically. At 2 vCPUs per environment, that is 1,000 environments.
The trade-off is granularity. One noisy route can consume the whole endpoint’s rateLimit, and per-route isolation exists only if routes live on separate endpoints or behind a front door that throttles per path.
When the Override Wins#
The default leans toward staying, because the gateway features the previous post preserved have no Web Function equivalent and the feature is new: one runtime, five Regions, no CDK L2. Three situations change the answer.
Greenfield Node.js HTTP services in a launch Region, with none of the blocking constraints, can start on a Web Function behind CloudFront with OAC and an IamAuth endpoint, using the same Hono app shape. There is no adapter to remove later and no gateway configuration to migrate. The cost is owning auth, CORS, and per-route policy in code from day one, plus accepting a cold start after idle periods, because there is no warm-capacity floor.
Streaming-heavy or long-request APIs should move first. Server-sent events, chunked responses, and requests longer than the gateway’s integration window fit Web Functions directly, while the Lambdalith needs Function URLs or a separate path for them. Handlers that spend most of their time waiting on I/O also fit the active-CPU billing model. The EnvironmentCPUTime to EnvironmentActiveTime ratio from the metrics page (opens in new tab) shows that share once a function runs.
Teams that should stay put include anyone on Python or Java, anyone who needs private REST APIs, per-route usage plans or API keys, or strict warm-capacity guarantees, and anyone whose traffic arrives from queues or streams. WebSockets are a fit for neither option; API Gateway WebSocket APIs remain the AWS answer there. For the earlier question of how many functions to have at all, see Single-Purpose Functions vs Lambdalith. The third form factor, MicroVMs, appears in Where Should Claude Code Run? as a sandbox option.
Mistakes the Documentation Already Warns About#
Each item below is a failure mode described in the launch documentation, with the fix AWS points to.
- Listening on
localhostor a fixed port. The result isApplication.TimeoutListenErroror a 502 on the first request. ParseAWS_LAMBDA_HTTP_ENDPOINTand bind exactly that host and port. - Trusting “Active”. An active revision or a successful endpoint update does not mean the server started; Lambda does not check that it listens. Smoke-test every deploy and read the logs.
- Partial configuration on a new revision. A new revision copies nothing from the previous one. Omitted environment variables disappear and the timeout returns to 30 seconds. Generate the full revision config from one source.
- Per-request state in module scope. It is shared by every request in flight on that environment. Use
c.setandc.get, and guard read-modify-write sequences that cross anawait. - EMF through
console. Lambda wraps the output and CloudWatch extracts nothing. Write withprocess.stdout.write. - Forwarding the viewer
Hostheader from CloudFront. Lambda routes onHostand answers 404Platform.InvalidEndpoint. Use theAllViewerExceptHostHeaderorigin request policy or an explicit allow list. If the app reads bearer tokens, also includeAuthorizationin the cache policy, or GET requests arrive without it. - Treating a front door as privacy. An
ApplicationManagedendpoint behind any front door stays reachable at its own domain, bypassing CloudFront and WAF. UseIamAuthwith OAC, or verify an origin secret in the app. - Writing the response before reading the body. The request path is half-duplex, so large uploads stall. Consume the body first.
- x86 native modules. Build dependencies inside a
linux/arm64container withnpm ci --omit=dev. - Trusting forwarded headers. Lambda forwards
X-Forwarded-Hostwithout validation and appends only the lastX-Forwarded-Forhop. Build absolute URLs from a domain you control. - Losing the rollback revision. Automatic cleanup removes the oldest unreferenced revisions past 50, and deleting the S3 object version moves a revision to Failed. Keep the rollback target referenced and its object version retained.
Where the Default Holds#
Keeping a working Hono Lambdalith on API Gateway holds while its routes depend on per-route scopes, throttles, usage plans, private APIs, or provisioned concurrency. It also holds for runtimes and Regions outside the launch list, and while none of the triggers apply. The override applies to greenfield Node.js services and to bounded contexts with long requests, streaming, I/O-heavy handlers, server-side rendering, or multi-Region latency needs. Those move path by path behind a front door that keeps a one-line revert. The next step that pays off either way is removing c.env.event and c.env.lambdaContext from the app.
References#
- AWS Lambda Web Functions (Developer Guide) (opens in new tab) - Overview of Web Functions: use cases, Node.js support, billing dimensions, and endpoint traffic controls.
- Announcing AWS Lambda Web Functions (AWS News Blog) (opens in new tab) - Launch post covering the three Lambda form factors, the
aws lambda-web deployworkflow, launch Regions, and CloudFront integration. - Core concepts for Web Functions (opens in new tab) - Resource model of functions, revisions, and endpoints, lifecycle states, and concurrency and timeout ranges.
- Lambda Web Function runtimes (opens in new tab) - The
nodejs24.xruntime,AWS_LAMBDA_HTTP_ENDPOINT, the Node.js execution model under concurrency, and memory defaults. - HTTP requests and responses (opens in new tab) - Supported methods, headers Lambda removes and adds, and the request-head size limit.
- Scaling behavior for Lambda Web Functions (opens in new tab) -
maxEnvironments,rateLimit, dynamic per-environment concurrency, and the worked capacity example. - Lambda Web Function endpoint access control (opens in new tab) -
IamAuthandApplicationManaged, request signing, and CloudFront Origin Access Control. - Configuring networking for Lambda Web Functions (opens in new tab) - Public endpoints, CloudFront front door setup, CORS responsibility, half-duplex requests, and the lack of WebSocket support.
- Deployment patterns (opens in new tab) - Auto-deployment modes, revision weights, canary and blue-green deploys, and rollback commands.
- Managing Web Function revisions (opens in new tab) - Revision properties and defaults, immutability, and automatic cleanup of old revisions.
- Using CloudWatch metrics with Lambda Web Functions (opens in new tab) - Built-in metric names and dimensions, including CPU and active-time metrics.
- Publishing custom metrics with the embedded metric format (opens in new tab) - Why EMF goes to standard output instead of
console, and dimension cardinality guidance. - Web Function sample applications (opens in new tab) - Express, Hono with
@hono/node-server, server-sent events, and packaging commands. - Best practices for Lambda Web Functions (opens in new tab) - Front door options, shared-secret verification behind non-CloudFront front doors, and request-scoped state under concurrency.
- Testing Lambda Web Functions (opens in new tab) - Local runs with
AWS_LAMBDA_HTTP_ENDPOINT, concurrent-request integration tests, and Arm64 package builds. - Troubleshooting Lambda Web Functions (opens in new tab) - The
lambda-web-error-typevalues and common startup, packaging, and HTTP failures. - Lambda quotas (opens in new tab) - Per-environment, per-endpoint, and per-account quotas for Web Functions next to Event Function limits.
- AWS::Lambda::WebFunctionEndpoint (CloudFormation) (opens in new tab) - Endpoint resource properties, replacement behavior, and revision weights in templates.
- JWK Auth Middleware (Hono) (opens in new tab) - Hono’s JWKS-based token verification middleware, its required
algoption, and payload access. - Restrict access to an AWS Lambda Web Function origin (CloudFront) (opens in new tab) - OAC setup, the
Authorizationcache policy requirement, and Lambda@Edge limits for Web Function origins. - AWS Lambda pricing (opens in new tab) - Current billing dimensions and rates for Web Functions.
Related posts
Move single-purpose Lambdas behind API Gateway into a Hono Lambdalith one route at a time, with a per-route rule for auth scopes, validation, throttling, and metrics.
lambda · serverless · api-gateway +3
Build a testing strategy for AWS Lambda, API Gateway, DynamoDB, and Step Functions with practical patterns for fast feedback and reliability.
lambda · testing · serverless +8
Set up a production-grade link shortener with AWS CDK, DynamoDB, and Lambda: architecture decisions, project layout, and the schema choices that hold up at scale.
aws-cdk · lambda · dynamodb +5
When a Lambda fleet outgrows Middy's static middleware model, how a project-specific engine handles per-request config, and what owning one costs
lambda · middleware · performance +6
Before building an internal service layer, decide whether you need one: what it costs per call, the volume where VPC Lattice wins, and when direct invoke still beats it.
aws · aws-cdk · lambda +4