Announcing native npm support on Deno Deploy
Deno Deploy makes it easy build and host any JavaScript app, function, or API server. Programming is faster and easier with Deno’s simple and robust APIs — web standard APIs, Node.js built-ins, and essential cloud services turned into first class JavaScript APIs, such as Deno KV (now in open beta). Your applications are run close to your users across 35 regions in the world, ensuring minimal latency and high availability.
Today, we’re excited to announce that Deno Deploy now natively supports
running npm modules via npm:
specifiers. This means you can now host Node.js
apps at the edge using the npm modules, all without the need for build steps.
Here’s an example of running an Express app on Deno Deploy:
// Import express and instantiate it
import express from "npm:express@4";
const app = express();
// Register a route
app.get("/", (req, res) => {
res.send("Hello World!");
});
// Run the server!
app.listen(3000);
Try it yourself in a Playground →
Deno Deploy is the first isolate based serverless platform to natively support Node.js built-ins and npm modules. This opens the door to a whole new world of possibilities for JavaScript developers — now even your Node.js apps can be hosted globally with minimal latency, high availability, and instant deploys.
Importing and using over 2 million npm modules integrates seamlessly with the rest of Deno: first-class TypeScript support, built-in tooling like the formatter, linter, and test runner, and the Deno Language Server that provides a rich editor experience in your IDE.
No bundle step needed
NPM and Node support in Deno is native — there is no transpilation, bundle step, or polyfill injection taking place. Deno Deploy natively understands Node.js APIs, and intrinsically knows how to load and execute NPM modules.
This has two main benefits for you: better developer experience and better compatibility.
We pride ourselves on Deno Deploy’s short feedback loop and instant deploys.
This extends to npm support as well. You can develop locally using npm:
specifiers and deploy to Deno Deploy via our seamless GitHub integration, going
from git push
to a live site in mere seconds.
Because we don’t transpile, bundle, and polyfill your code or any npm modules you import, there are no steps like these to introduce issues. This means that code that works locally will work on Deno Deploy, and vice versa.
Since there’s no bundling or source mapping, if anything does go wrong, your Deno Deploy stack traces and logs show file names and line numbers that match up with what you see locally — no more digging through unintelligible minified and bundled code.
Examples and use cases
Here are a few examples of what you can build with npm packages on Deno Deploy.
Fastify
Fastify is a popular solution for building API servers and web applications in Node.js. With npm specifier support on Deno Deploy, it’s now usable in your web apps running on the edge as well.
Try it yourself in a Playground →
// Import the framework and instantiate it
import Fastify from "npm:fastify@4";
const fastify = Fastify();
// Declare a route
fastify.get("/", async function handler(request, reply) {
return "Hello World!";
});
// Run the server!
await fastify.listen({ hostname: "localhost", port: 3000 });
Deno.serve + OpenAI
NPM support is not limited to web frameworks. You can use it to power up any existing Deno app by importing packages from NPM. For example, you can use the OpenAI SDK to enhance your application with state-of-the-art AI completions.
Try it yourself in a Playground →
import OpenAI from "npm:openai@4";
const openai = new OpenAI({ apiKey: Deno.env.get("OPENAI_API_KEY") });
Deno.serve(async (req: Request) => {
const completion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: "Tell me a programmer joke" }],
});
const joke = completion.choices[0].message.content;
return new Response(joke);
});
Crypto APIs
Encryption and decryption is one of that most popular categories of modules on
npm. Here’s an example using crypto-js
, one of the
top packages on npm.
Try it yourself in a Playground →
import CryptoJS from "npm:crypto-js@4";
Deno.serve((_req: Request) => {
// Encrypt
const ciphertext = CryptoJS.AES.encrypt("my message", "secret key 123")
.toString();
// Decrypt
const bytes = CryptoJS.AES.decrypt(ciphertext, "secret key 123");
const originalText = bytes.toString(CryptoJS.enc.Utf8);
return new Response(originalText);
});
Compatibility
Deno Deploy supports all 47 of Node.js built-in modules, such as fs
, path
,
and http
. You can import them directly via node:
specifier, just like in
Node.js.
Any npm package relying on these APIs will work on Deno Deploy. For example, the
aws-sdk
package, which uses http
internally, just works:
Try it yourself in a Playground →
/** @jsx jsx */
/** @jsxFrag Fragment */
import { Hono } from "https://deno.land/x/hono@v3.5.8/mod.ts";
import { Fragment, jsx } from "https://deno.land/x/hono@v3.5.8/middleware.ts";
import { DynamoDBClient } from "npm:@aws-sdk/client-dynamodb@3";
import {
DynamoDBDocumentClient,
ExecuteStatementCommand,
} from "npm:@aws-sdk/lib-dynamodb";
import { fromEnv } from "npm:@aws-sdk/credential-providers@3";
// Init DynamoDB client
const client = new DynamoDBClient({
region: "us-east-2",
credentials: fromEnv(),
});
const docClient = DynamoDBDocumentClient.from(client);
// Init Hono app
const app = new Hono();
// List TODOs
app.get("/", async (c) => {
const command = new ExecuteStatementCommand({
Statement: "SELECT * FROM Todos WHERE complete = ?",
Parameters: [false],
ConsistentRead: true,
});
const response = await docClient.send(command);
console.log(response);
return c.html(
<html>
<body style={{ margin: "10px auto", maxWidth: "400px" }}>
<h1>TODOs</h1>
<form action="/" method="POST">
<input type="text" name="text" />
<button
type="submit"
style={{
display: "inline-block",
marginLeft: "5px",
}}
>
Add Item
</button>
</form>
{response.Items.map((item) => {
return (
<div style={{ margin: "5px 0" }}>
{item.text}
</div>
);
})}
</body>
</html>,
);
});
// Add a TODO item
app.post("/", async (c) => {
const body = await c.req.parseBody();
const command = new ExecuteStatementCommand({
Statement: `INSERT INTO Todos value {'text':?, 'complete':?}`,
Parameters: [body.text, false],
});
try {
const response = await docClient.send(command);
console.log(response);
} catch (e) {
console.error(e);
}
return c.redirect("/");
});
Deno.serve(app.fetch);
While our Node.js compatibility is very good at this point, there are still some Node.js APIs that are not supported, or are not yet entirely compatible with the Node.js implementation.
There are also some npm packages that will not work on Deno Deploy. Any packages
relying on NodeAPI (the native plugin layer for Node), will not work with a
serverless system like Deno Deploy due to sandboxing restrictions. The same
security sandbox also prevents some Node.js APIs from working, such as
child_process
and vm
.
If you run into any issues using a specific npm module on Deno Deploy, please open an issue here.
What’s next
With npm support and Deno KV in open beta, your JavaScript app can access over two million modules and unlock more functionality, provide a productive and intuitive development experience (like connecting to a globally distributed database in a single line of code), and offer a fast global deployment process that hooks right into your git workflow. All that while offering your end users minimal latency and high availability.
We’re working hard to add important useful features to further simplifiy building and hosting complex, production-ready apps. We have many exciting announcements coming up, so stay tuned!
Don’t miss any updates! Follow our Twitter, join our Discord, and subscribe to our YouTube channel.