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.
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
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?