Pulse x reMKTR

AWS Lambda runtime updates you can use right now

Written by Jacob Heinz | Nov 17, 2025 8:34:30 PM

Rust just went GA on AWS Lambda, and that’s a big swing. Java 25 landed too, right on time for fall deployments. SnapStart cuts cold starts by up to 10x without extra math. You also get cleaner logging costs and standardized init billing across functions. If you run serverless in prod, this week’s drop is a budget lever.

You’re getting more languages, faster startups, and knobs that map cost to reality. And yes, we’ll cover Node.js 20 versus Node.js 24 on Lambda. We’ll show the safest upgrade path without breaking your pipeline, or your weekend.

Here’s the play: ship faster code with Rust, and modernize JVMs with Java 25 plus SnapStart. Tighten observability with CloudWatch logs, and keep AI agents measurable with Bedrock metrics via Lambda. By the end, you’ll know which runtime to pick and why it matters. You’ll learn how to update-function-code without downtime and trim real dollars from logs.

If you’ve been juggling cold starts, noisy logs, and runtime EOL warnings, breathe. This is your clean reset, with moves you can repeat next quarter. Dial in speed, stabilize costs, and set up a rollout muscle you’ll reuse. Nothing flashy here—just practical upgrades that make prod feel boring, in a good way.

Expect clear steps, safe defaults, and real examples you can copy-paste today. Think of this like your week-one plan to move fast without 2 a.m. alerts.

TLDR

  • Rust runtime is GA on Lambda; great for speed and memory safety.
  • Java 25 support + SnapStart = dramatically faster cold starts.
  • Experimental Swift runtime interface client expands options.
  • CloudWatch Logs tiered pricing + new destinations lower costs.
  • Lambda init-phase billing is now standardized for clarity.
  • Node.js 20 is rock-solid; Node 24 requires a plan (custom image/runtime).

Rust serverless performance cheat code

Why Rust on Lambda matters

You want faster, safer functions without a garbage collector pause mid-request. Rust gives you both, and then some without drama or surprise. With the Rust runtime now generally available on AWS Lambda, it’s go time. The runtime interface client also hit v1.0.0, which is nice. You can build low-latency handlers that stay stable under bursty load.

Rust’s compile-time safety wipes out whole classes of production bugs, like data races. It also slams the door on nulls and keeps memory tight and predictable. That matters when you’re billed by duration and every millisecond counts. If Python starts wheezing on CPU-heavy tasks, Rust will carry the load.

If you’ve tiptoed around Java due to startup overhead, Rust is a clean move. Think JSON transformation at scale and steady event enrichment work. Think image processing or pre-LLM feature extraction without jitter. You’ll feel the smoothness as traffic spikes and resets.

Beyond raw speed, Rust wins on predictability under stress and bursts. No GC means fewer latency spikes when it matters most. Smaller memory footprints let you right-size functions with confidence. You won’t need to over-provision RAM just to feel safe anymore.

The AWS Rust ecosystem also matured a lot, which really shows. You’ve got crates for Lambda handlers and structured logging that don’t bloat. You’ve got metrics and a solid AWS SDK so your code stays focused. The pieces fit clean and don’t fight you during build or deploy.

Practical wins you’ll notice:

  • Stable p95 and p99 latency under bursty traffic and weird spikes
  • Lower tail latency on stacked, concurrent invocations under pressure
  • Flat memory usage over long runs with no slow drift creeping in
  • Fewer retries from flaky timeouts and noisy neighbors in bursts

Ship Rust to Lambda

A straightforward path that just works in most shops:

  • Build a static binary for Linux on x86_64 or arm64 using Cargo.
  • Use the official Rust Lambda crates to wire up your handler function.
  • Zip the binary and push with the CLI so you keep it simple.

Example flow you can copy:

  • Build: cargo build --release --target x86_64-unknown-linux-gnu
  • Package: zip function.zip bootstrap (name your binary bootstrap if you’re using the Runtime API)
  • Deploy: aws lambda update-function-code --function-name my-rust-fn --zip-file fileb://function.zip

First-hand example: migrate a Python JSON sanitizer to Rust this week. Keep the exact logic, just port and measure behavior under load. The Rust build trims duration variance and holds memory flat nicely. You’ll likely reduce configured memory and also total cost. You won’t need to touch concurrency or rush alarms.

Pro tip: target AWS Graviton arm64 for better price and performance. If you need fast local iteration, use a container image. Wrap your binary and run it with docker before you ship to prod.

Extra polish for a smooth Rust rollout:

  • Prefer arm64: build with --target aarch64-unknown-linux-gnu to run on Graviton.
  • Keep the binary lean: compile in release and prune unused features. Use Cargo feature flags to keep extras off by default.
  • Structured logs: add tracing with a JSON formatter and write to stdout. CloudWatch will parse fields and keep it tidy.
  • Metrics: emit custom metrics via PutMetricData or log-embedded dimensions. Wire alerts to p95 latency and error counts right away.
  • Native deps: cross-compile inside an Amazon Linux container. That matches Lambda’s environment and avoids runtime surprises.

Measuring the win the right way:

  • Baseline current runtime for a week, include p50 and p95 with memory. Track cold and warm split plus error rate across bursts.
  • A/B on a canary alias by sending Rust ten percent of traffic first. Compare tail latency and errors before you flip the rest.
  • Tune memory: bump RAM until duration flattens clearly, then stop increasing. Use AWS Lambda Power Tuning to find the sweet spot.

Java 25 SnapStart cold starts

What Java 25 changes for functions

Java on Lambda has matured a lot, and Java 25 tightens the loop. AWS notes improved startup characteristics and lower overhead versus older releases. That matches what you actually care about on busy endpoints. Sub-second p95s and predictable init when traffic gets weird.

If you’re on Java 11 or 17 because that’s where the team settled, fine. You can finally justify the switch with real, measurable gains. It’s especially true for functions that spin frameworks or heavy classloading. That first hit will feel lighter and less spiky under load.

Key benefits you’ll feel in production environments quickly:

  • Faster cold starts even before you touch SnapStart configuration
  • Newer JIT optimizations and runtime improvements across common paths
  • Cleaner path to adopt newer libraries and timely security updates

Small but meaningful tweaks add up really fast across busy services. Faster classloading and better default GC behavior reduce noise. Modern language features also let you simplify code and tests. If plugins blocked you before, re-check vendor support matrices now.

SnapStart performance lever

For Java functions, SnapStart pre-initializes your execution environment cleanly. It restores from a snapshot on cold starts with no extra cost. You can see up to 10x faster first-hit performance on endpoints. Perfect for APIs and event flows where every millisecond matters a lot.

Action plan that fits most teams without extra tools:

  • Enable SnapStart on your Java 25 function in console or CLI.
  • Move expensive setup into static init blocks and keep them pure.
  • Confirm initialization is deterministic and won’t leak per-instance state.

First-hand example: a Spring Boot Lambda using Provisioned Concurrency today. You flip to Java 25 with SnapStart enabled and measure again. You keep peak performance and drop steady-state costs immediately. No more pre-warming instances around the clock for safety.

Caveats: encrypt secrets correctly and avoid freezing raw credentials. Re-check library compatibility with SnapStart before you roll broadly. Monitor Init Duration and cold start metrics to validate the change. Keep dashboards visible to the team during rollout.

More SnapStart hygiene you should follow:

  • Randomness: don’t seed PRNGs during snapshot; reseed on first invoke. That avoids reused entropy and security issues later.
  • Connections: don’t rely on open sockets from snapshot images. Reconnect on restore or lazily on first real use.
  • Caches: in-memory caches baked into snapshots can go stale quietly. Validate TTLs or rebuild on restore to stay correct.
  • Observability: confirm X-Ray or telemetry IDs are per-invoke. Don’t bake a single ID into the snapshot by accident.

How to validate the impact with real traffic:

  • Before and after on the same function name using aliases. Keep infra identical and only change what’s needed.
  • Track cold-start median and p95 for a full day with spikes. Include deploy events and cron bursts to see edges.
  • Compare cost and remove provisioned concurrency if no longer needed. Do the math and decommission it to realize savings.

Swift experiments and runtimes

Swift experimental runtime client

Swift isn’t just for iOS, not anymore really. With an experimental runtime interface client, Swift on Lambda is open. You can trial serverless Swift for backend endpoints or build tools safely. Also handy for Apple ecosystem workflows tied to releases.

It’s experimental, so treat this as a careful pilot, not a bet. Wrap critical logic in tests and stage traffic slowly to prove stability. Keep a rollback alias ready so mistakes don’t hurt users. Learn fast and only then expand to more flows.

If your team ships Apple apps and already lives in Swift daily, try it. One language across CI tools and app metadata processors feels great. Even lightweight API handlers tied to your build process can benefit, honestly. Cohesion wins when context switches drop for the team.

Practical tips if you test Swift in a real project:

  • Keep dependencies slim to reduce binary size and startup time.
  • Cross-compile using an Amazon Linux compatible container to match Lambda.
  • Prefer arm64 for price and performance, especially on Apple silicon dev machines.
  • Gate traffic behind a feature flag and keep a short rollback window.

Node 20 and 24 plan

Node.js 20.x is a stable, supported runtime on Lambda today. It’s a safe default for production across most teams. If you’re still on Node 16 or 18, it’s time to move. You’ll gain performance, security fixes, and nicer ESM ergonomics right away.

About Node.js 24: Lambda might not have first-class support yet everywhere. If it’s not listed for your region or account, you’ve got two paths. Both are straightforward and well known in most shops today.

  • Container image: package Node 24 in an AWS Lambda base image. Ship it as a container and pin versions tightly.
  • Custom runtime: use the Runtime API and bring your own bootstrap with Node 24.

Either way, pin dependencies and run your full test suite in CI. Use the exact image you deploy to avoid surprise behavior later. When managed Node 24 lands in Lambda, watch the runtimes page. Then switch your function config with one clean command in place.

  • aws lambda update-function-configuration --function-name my-fn --runtime nodejs20.x (replace when 24 is supported)

First-hand example: upgrade a Node 18 API to Node 20 this sprint. Bump the runtime, repackage, and ship your new ZIP bundle. Run: aws lambda update-function-code --function-name my-fn --zip-file fileb://dist.zip. Shift ten percent traffic via alias and watch latency and errors. Give it thirty minutes before going one hundred percent safely.

Helpful Node upgrade guardrails that catch most issues:

  • Build for the right arch and use Amazon Linux for native deps.
  • Bundle smart and tree-shake to keep your ZIP small for speed.
  • Use AWS SDK v3 modular clients to reduce size and init time.
  • Test ESM and CJS edges so loaders match runtime expectations.

Cost and ops toolkit

Logging costs and destinations

CloudWatch Logs added tiered pricing and expanded destination options. That’s huge if your Lambda fleet gets chatty often. You can keep high-signal logs hot and move the rest cheaper. Your bill will start reflecting actual value, not just volume.

Strategy you can roll out without painful refactors:

  • Separate hot and cold logs by intent and signal strength. Keep structured, high-signal events in hot storage for quick lookups.
  • Stream verbose debug to S3 via Kinesis Firehose with lifecycle rules. That preserves detail without burning money on routine storage.
  • Drop PII at the edge and filter before it hits any store. Add filters at the app layer so junk doesn’t sneak in quietly.
  • Sample where it won’t hurt your understanding of system health. High-volume, low-value traces can be sampled safely.

First-hand example: move JSON debug logs to S3 with lifecycle rules enabled. Retain for thirty to sixty days depending on compliance needs. Keep only errors and warns in CloudWatch for quick triage. You preserve forensic depth and shrink the recurring bill nicely.

More levers you can pull with low risk and high payoff:

  • Subscription filters: route patterns to a processing Lambda or Firehose. Or send to a partner tool for cheaper storage and search.
  • Data protection: use CloudWatch Logs data protection to mask sensitive data. Detect and scrub before it lands in storage anywhere.
  • Retention defaults: set short default retention at log group creation. Seven to fourteen days by default, extend only for critical groups.
  • Compression and format in S3: write NDJSON or Parquet to cut storage. Then speed queries with Athena when you need deep dives.

Billing clarity and AI metrics

Lambda’s billing for the initialization phase is now standardized clearly. Your cost model finally matches how your code behaves. Cold starts won’t feel like a black box anymore frankly. You can measure it and decide with real numbers.

You should do a few simple things this week:

  • Track init duration as a first-class metric on dashboards.
  • Shift heavy setup into SnapStart-friendly paths for Java functions.
  • Lazy-load where it makes sense to keep cold starts lighter.
  • Right-size memory by measuring duration versus cost per runtime.

On the AI side, Amazon Bedrock Agents can publish detailed metrics. They can send CloudWatch metrics via Lambda for clean visibility. Intelligent Prompt Routing is generally available as well. If you orchestrate model calls from Lambda, you get strong insights.

That combo gives you per-agent latencies and success rates by call. It also helps smarter model selection by cost and quality goals. Pair it with structured logging and you get a tight feedback loop. You can test prompts in production without flying blind anymore.

First-hand example: a chatbot orchestrator Lambda logs token usage and latency. It exports key metrics to CloudWatch for easy alerting and graphs. Intelligent Prompt Routing picks a cheaper model for simple requests automatically. You hit SLAs and drop spend without changing the UI at all.

Reality check on costs that holds up under audits:

  • Cold starts are less scary when you can observe and attribute init. Clear metrics make trade-offs obvious and repeatable.
  • Memory tuning often beats code tweaks for immediate savings fast. Measure before refactoring and stop guessing under pressure.
  • If logs are your biggest bill after compute, you’ve got instant wins. Move verbose streams and set firm retention everywhere.

Runtime upgrade playbook

Map estate and deprecation

Step one: inventory every Lambda function and runtime with region and alias. Tag owners and business criticality so nothing falls through. If you’re on older Node, Python, or Java versions, set deprecation dates. Get buy-in early so timelines don’t slip again.

A runtime upgrade is a great moment to pay down tech debt. Clean up env vars and logging format with a single standard. Tighten IAM scoping while you’re in there already touching config. You’ll thank yourself when audits show up, trust me.

Checklist for each function before you touch anything:

  • Runtime and memory size with clear defaults captured in code
  • Dependencies and native binaries you must compile correctly
  • Cold start profile including init duration and SnapStart eligibility
  • Observability coverage including logs, metrics, and tracing paths

First-hand example: a payments workflow with five Lambdas stuck on Node 16. You batch the upgrade to Node 20 within one sprint cleanly. Align secrets to AWS Secrets Manager as the one source. Standardize JSON logs, and cap CloudWatch retention at thirty days.

Add process glue so teams move smoothly and independently:

  • Infrastructure as code: capture runtime, memory, timeouts, and env vars.
  • Pre-flight checks: scan for deprecated Node APIs or Java libs proactively.
  • Parallel tracks: split by runtime family so teams can ship alone.

Deploy with safety rails

Your two levers are update-function-configuration and update-function-code. Use them in a controlled pipeline with clear checkpoints and alarms. Keep the blast radius tiny while you learn how the new runtime behaves. Let CodeDeploy manage the traffic shift with canaries.

  • Build artifact
  • Deploy new version
  • Shift traffic with an alias, canary ten percent then one hundred
  • Watch error rates, duration, memory, and cold starts closely
  • Roll back by pointing the alias to the previous version quickly

Commands you’ll actually use in the real world:

  • Update runtime: aws lambda update-function-configuration --function-name my-fn --runtime nodejs20.x
  • Update code: aws lambda update-function-code --function-name my-fn --zip-file fileb://dist.zip
  • Publish version: aws lambda publish-version --function-name my-fn
  • Point alias: aws lambda update-alias --function-name my-fn --name prod --function-version 42

First-hand example: moving a Java 17 analytics function to Java 25 now. You enable SnapStart, redeploy, and run a fifteen-minute canary. Confirm p95 dropped on cold hits, then lock it with an alias. Close the ticket and move to the next function calmly.

Bonus guardrails that save you when nerves spike:

  • Health bar: set CloudWatch alarms on 5xx rate, duration, and init duration. Tie them to the canary alias so noise stays low.
  • Freeze window: block deploys for thirty minutes after go-live. Keep the system stable while metrics settle and recover.
  • Rollback muscle: always keep the N-1 version warm and documented. Practice the rollback so it’s muscle memory under stress.

Quick pit stop summary

  • Rust runtime is GA and ships real performance gains for CPU-heavy tasks.
  • Java 25 + SnapStart gives you cold-start wins without provisioned concurrency.
  • Swift’s experimental client is worth a pilot if you’re deep in Apple ecosystems.
  • Node.js 20 is the safe target now; plan Node 24 via containers/custom runtime until native support lands.
  • CloudWatch Logs: push verbose streams to S3, keep high-signal logs hot.
  • Init-phase billing is standardized; track it and optimize your startup path.

FAQ runtime and rollout

  1. Q: Is Node.js 24 supported on Lambda today? A: Node.js 20 is supported broadly and safe to use right now. For Node 24, check the Lambda runtimes page before planning. If it’s not listed yet, deploy via a Lambda container image. Or use a custom runtime using the Runtime API for clean control. When native support appears, switch your function runtime with one update.

  2. Q: Should I move all Java functions to Java 25 immediately? A: Prioritize functions that are user-facing or cold-start sensitive today. Java 25 improves startup and trims init overhead in practice. If you can enable SnapStart, you’ll see the biggest impact there. For batch or async jobs, the benefit is smaller but still real.

  3. Q: What’s the simplest way to try Rust on Lambda? A: Start with one CPU-bound function, like parsing or enrichment. Compile for Linux, package the binary, and deploy with update-function-code. Measure duration and memory versus your current runtime baseline. If performance stabilizes or costs drop, expand the footprint confidently.

  4. Q: How do I keep CloudWatch Logs costs in check without losing visibility? A: Separate signals and pick the right store for each type. Errors and warns stay in CloudWatch with shorter retention periods. Verbose and debug streams go to S3 via Firehose with lifecycle rules. Add sampling and sanitize payloads at the edge every time.

  5. Q: Does SnapStart change my security posture? A: Treat snapshots like production memory with the same care. Don’t embed secrets directly in static initializers in any case. Use Secrets Manager or Parameter Store and fetch at restore-time. Validate that all libraries support snapshot and restore semantics.

  6. Q: What’s the difference between update-function-code and update-function-configuration? A: Code updates ship new artifacts via ZIP or container image. Configuration updates change runtime, memory, env vars, or timeouts. In practice, you’ll use both in a release with a canary. Push code, publish a version, then point an alias and observe.

  7. Q: Arm64 or x8664 for Lambda? A: Prefer arm64 Graviton for better price and performance when possible. Test native modules and compile binary addons for arm64 correctly. If a dependency blocks you, stick with x8664 until you can swap. Keep the migration on your backlog with owners and dates.

  8. Q: ZIP or container images for deployment? A: Use ZIP for small, simple functions to move fast and easy. Choose container images when you need custom runtimes or system packages. They also shine with large dependencies or language previews. Keep images slim to reduce cold start and pull time.

  9. Q: Do VPCs still hurt cold starts? A: VPC networking is much better than it used to be, honestly. There’s still overhead on first attach during cold starts though. Keep Lambdas out of VPC unless they need private resources. If they must, warm critical paths or use SnapStart for Java.

  10. Q: X-Ray or OpenTelemetry for tracing? A: If you’re all-in on AWS tooling, start with X-Ray for simplicity. If you’re multi-cloud, use OpenTelemetry and ship traces where needed. Either way, don’t skip tracing on public-facing functions please. It pays off during incidents and postmortems every single time.

10 step runtime upgrade checklist

  • Inventory functions by runtime, region, and owner; tag critical paths.
  • Decide targets: Rust for CPU-heavy, Java 25 + SnapStart for JVM apps, Node 20 for JS today.
  • Create an observability baseline: p50/p95 latency, errors, cold-start rate, memory.
  • Build and test artifacts on the exact Linux architecture (x86_64/arm64).
  • Deploy to a staging alias; run load tests mirroring production traffic.
  • Use update-function-configuration to switch runtimes; publish a version.
  • Canary with CodeDeploy: 10% traffic first; monitor metrics and logs.
  • Tune memory for perf and cost sweet spot; re-run the canary test.
  • Cut over to 100%; keep the old version for instant rollback paths.
  • Trim CloudWatch retention, stream verbose logs to S3, and set alerts on init duration.

You’re looking at a rare alignment across speed, language options, and costs. More speed, better choices, and costs that map to reality well. The big win isn’t just shaving milliseconds off a graph. It’s building a rollout muscle you can reuse for every bump.

If you remember one thing, pick one function and upgrade it this week. Measure the results and write them down for the next sprint. Momentum compounds more than we think when we keep it moving.

Building Lambda-based pipelines for Amazon Marketing Cloud? Streamline them with AMC Cloud and automate query orchestration with Requery.

“A good serverless upgrade is boring: precise inventory, small canary, measurable win.”

References