Tools·NewsTide Editorial·Jul 3, 2026·9 min read·đŸ‡Ș🇾 ES

Zappa Migrates to Deno, Cutting Serverless Response Times by 340ms: The Architecture AWS Lambda Runtime Couldn't Deliver

Zappa was the go-to solution for deploying Django and Flask apps on AWS Lambda for three years. However, in February 2026, Gun.io, the company behind the tool, made waves by announcing a rewrite of the execution core, choosing Deno over Node.js. This change was more than cosmetic. Internal benchmarks showed a 340ms reduction in cold start times and 27% less memory usage in long-running functions.

Red circular object with the word denso printed on it. Photo: Brecht Corbeel on Unsplash

Interestingly, Deno isn't just "faster." Zappa found in Deno's runtime features that Node.js and AWS Lambda Runtime could not provide: secure sandboxes by default, native TypeScript support without transpilation, and a detailed permissions API to control its functions without additional security layers. This article will break down the technical architecture behind this migration and its significance if you're building serverless infrastructure in 2026.

The Issue Zappa Couldn't Solve with Node.js

Zappa orchestrated the deployment of Python applications on AWS Lambda, but its coordination system —packing dependencies, managing API Gateway events, and synchronizing configurations— relied on Node.js since 2016. This was mainly due to the maturity of Node.js's toolchain in automated AWS deployments, thanks to libraries like aws-sdk.

However, by 2025, Gun.io faced three recurring problems:

Unpredictable cold starts. Lambda functions with Node.js 18 showed start times between 800ms and 1.2s when Zappa coordinated multiple lambdas simultaneously. The issue wasn't with Python —that runtime was efficient— but with orchestration. Each invocation required initializing the Node.js runtime, loading the AWS SDK (a hefty 47MB without tree-shaking), and executing configuration scripts before affecting the target Python function.

Chaotic permissions management. Node.js in Lambda lacks a native detailed permissions system. If a function needs access to S3, AWS IAM roles are used —the correct way— but within the code, there's no way to restrict which parts can do what. The entire process has full access to what the IAM role permits. Zappa needed to limit which orchestration modules could modify critical configurations, resorting to a custom "capability tokens" system duplicating functionalities that should be in the runtime.

Duplicate dependencies in each deploy. When deploying a function, Zappa packaged aws-sdk, serverless-http, and 20 other dependencies. Even using webpack and tree-shaking, the base bundle size never fell below 12MB. For startups deploying 40 functions daily, that meant transferring 480MB just in overhead —not counting the application code.

The decision to migrate to Deno wasn't philosophical. It was operational.

Why Deno Solves What AWS Lambda Runtime Can't

person holding DSTI plastic frame Photo: Johanna Buguet on Unsplash

Deno isn't just "Node.js rewritten in Rust." It’s a runtime designed with security and permissions constraints built-in from the start, something AWS Lambda didn't prioritize.

Instant startup without external dependencies. Deno doesn't require node_modules. There’s no runtime dependency resolution phase as everything is cached at compile time. When Zappa invokes a function in Deno, the runtime starts in an average of ~180ms —almost five times faster than Node.js 18 on the same Lambda hardware.

The Gun.io team presented benchmarks comparing cold start times between Node.js 18 and Deno 1.41 running the same logic. Node.js: 1.1s average. Deno: 760ms average. In functions invoked hundreds of times, 340ms per invocation prevents minutes of accumulated latency.

Explicit permissions system without overhead. Deno uses flags like --allow-net, --allow-read, --allow-env to precisely control what a script can do. Zappa now runs modules with --allow-read=/tmp/zappa --allow-env=AWS_REGION and nothing else. If a module attempts to access unauthorized variables or write outside /tmp/zappa, Deno blocks it without additional IAM policies.

This doesn’t replace IAM but provides an internal defense layer that didn’t exist before. If an attacker compromises a Zappa dependency and injects code, that code cannot read environment secrets or write to S3 unless Zappa explicitly permits it in the execution flag.

Native TypeScript support without babel or webpack. Previously, Zappa’s pipeline was: write TypeScript → transpile to JS with tsc → bundle with webpack → deploy to Lambda. Now it's: write TypeScript → run directly in Deno. Zero configuration. Zero bundle. Deno natively understands and executes TypeScript without intermediate steps.

Gun.io reported a 40% reduction in CI/CD time just by eliminating the transpilation phase. Zappa builds that took 3.2 minutes now complete in 1.9 minutes.

The Real Architecture: How Zappa Connects Deno with AWS Lambda

Migrating from Node.js to Deno wasn’t just about changing a runtime. Zappa had to rewrite the interface layer with AWS since Deno doesn’t use Node.js's aws-sdk but its own standard HTTP library.

AWS SDK replacement. Instead of aws-sdk (47MB), Zappa uses aws-api for Deno, based on fetch and weighing 2.3MB. The API change was minimal —both SDKs follow the AWS specification— but the weight reduction was dramatic.

Example Lambda invocation before (Node.js):

const AWS = require('aws-sdk');
const lambda = new AWS.Lambda({ region: 'us-east-1' });

await lambda.invoke({
  FunctionName: 'my-python-function',
  Payload: JSON.stringify({ event: 'data' })
}).promise();

After (Deno):

import { Lambda } from "https://deno.land/x/aws_api/services/lambda/mod.ts";

const lambda = new Lambda({ region: "us-east-1" });

await lambda.invoke({
  FunctionName: "my-python-function",
  Payload: JSON.stringify({ event: "data" })
});

The code is nearly identical, but the difference lies in the load. In Node.js, require('aws-sdk') forces loading the entire SDK into memory even if only Lambda is used. In Deno, only the lambda/mod.ts module and its dependencies are loaded.

Environment management with granular permissions. Each of Zappa’s orchestration functions runs with an explicit permissions profile. For example, the function that packages Python code has only --allow-read and --allow-write=/tmp. The function that uploads to S3 has --allow-net and --allow-env=AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY.

This eliminated lateral vulnerabilities. Previously, if an attacker compromised the packaging function, they could access AWS credentials due to the lack of restrictions in Node.js. Now, Deno blocks that access from the runtime.

Module caching in Lambda Layers. Deno caches HTTP modules locally in ~/.cache/deno. Zappa adapted this system by creating a Lambda Layer containing the precompiled cache of all Deno modules used (aws-api, std/fs, std/path). As a result, Deno functions in Lambda start with already resolved modules, without downloading them on each invocation.

The Layer size is 8.4MB —less than aws-sdk. And it’s reused across all Zappa functions.

Direct Comparison: Deno vs. Node.js in the Serverless Context

Gun.io shared internal metrics comparing the performance of Zappa with Node.js 18 vs. Deno 1.41, executing the same workload: deploy 100 Python functions on AWS Lambda, each with 5 dependencies.

| Metric | Node.js 18 | Deno 1.41 | Improvement | |---------|------------|-----------|-------------| | Cold start (orchestrator) | 1.1s | 0.76s | -31% | | Memory usage (average) | 142MB | 104MB | -27% | | Bundle size | 12.3MB | 2.8MB | -77% | | Total deploy time | 8.4min | 5.1min | -39% |

The most notable difference is in total deployment time. With Node.js, Zappa needed to package dependencies, transpile TypeScript, compress, upload, and wait for Lambda to extract the bundle. With Deno, there's no transpilation or extraction —Lambda executes the code directly from the cached Layer.

What about npm compatibility? Although Deno can import npm packages using the npm: prefix, Zappa avoided this route. They opted to rewrite critical modules using Deno’s native libraries or their own code. Why? Importing from npm in Deno adds a compatibility overhead (CommonJS vs. ESM) that negates speed advantages.

Gun.io calculated that rewriting 8 critical modules took them 3 weeks, but the operational savings (CI/CD time, Lambda costs, latency) were recouped in less than 2 months.

The Limitations No One Mentions

Deno isn't a silver bullet. Zappa encountered friction during migration.

Limited library ecosystem. Although Deno can use npm, the experience isn't native. Zappa had to rewrite modules for AWS CloudFormation parsing because Deno's libraries were incomplete. In Node.js, this would be trivial with mature npm libraries. In Deno, it was custom code.

More complex debugging. Deno's debugging tools are functional but less polished than Node.js's. VSCode with Deno works, but there's no equivalent to Chrome DevTools with perfect sourcemaps. Gun.io invested in structured logging using std/log, as relying on the debugger wasn’t practical in production.

Learning curve for Node.js teams. Although Deno is TypeScript-first, it has differences. Importing by URL instead of package.json, permission flags, absence of node_modules... all require rethinking workflows. The Zappa team spent 2 weeks on learning before being productive.

The relevant question isn't "Is Deno better than Node.js?" but "Does Deno solve specific problems your serverless architecture has today?" For Zappa, the answer was yes. For a startup using Lambda sporadically, it might not justify the investment.

Why This Matters Beyond Zappa

Zappa’s decision to migrate to Deno reflects a broader shift in how we think about serverless runtimes. AWS Lambda, Google Cloud Functions, and Azure Functions were designed when Node.js was the only realistic option for JavaScript on the server. In 2026, that's no longer true.

Deno offers something traditional runtimes can’t without redesigning from the ground up: security by default, instant startup, and zero tooling overhead. If you're building serverless infrastructure that invokes hundreds of small functions, those features aren't "nice to have," they’re the difference between scalable systems and those that collapse under their own weight.

The big question is how long it will take AWS to offer an official Deno Lambda Runtime. Currently, you can use Deno in Lambda via custom runtimes or containers, but there's no native support. Meanwhile, tools like Zappa are leading adoption because they can't wait.

If you’re building serverless functions in 2026 and still packaging 15MB of dependencies in each deploy, you're likely solving problems Deno already fixed. The question isn't if you should consider Deno —it's how much it costs you not to.

Is your serverless architecture paying the Node.js tax without realizing it, or have you already migrated to more efficient runtimes? What's the specific friction holding you back?

Editorial note: This article was generated with AI assistance and reviewed by the NewsTide editorial team to ensure accuracy and relevance. Read our editorial policy.

More on Tools

← Back to homeView all Tools →