DEV Community

Cover image for Turn Your Web App into a Desktop App with Deno
Med Marrouchi
Med Marrouchi

Posted on

Turn Your Web App into a Desktop App with Deno

Deno is no longer “just” a modern JavaScript and TypeScript runtime for servers, scripts, and CLIs.

With Deno Desktop, you can package a Deno app as a real desktop application for macOS, Windows, and Linux.

Think of it as a lightweight way to ship a web-based UI inside a native desktop window, without having to rewrite your app in another language or move your backend logic somewhere else.

In this post, we will build a small Hello World desktop app using Deno.

Note: At the time of writing, deno desktop is part of the upcoming Deno 2.9 release and is available through the canary build.

What is Deno Desktop?

Deno Desktop lets you take a Deno project and run it as a desktop application.

Under the hood, your app still behaves like a web app. You serve HTML, CSS, JavaScript, and API routes using Deno.serve(). Deno then opens that local app inside a desktop window.

That means you can keep a very familiar architecture:

Deno app
  ├── serves HTML
  ├── exposes local API routes
  ├── runs TypeScript
  └── opens inside a native desktop window
Enter fullscreen mode Exit fullscreen mode

For many apps, this is a very attractive model.

You can use web technologies for the UI, Deno for the backend logic, and still distribute the result as a desktop app.

Installing the Deno Canary Build

Since Deno Desktop is currently available in canary, install or upgrade to the canary version:

deno upgrade canary
Enter fullscreen mode Exit fullscreen mode

Then verify that Deno is installed:

deno --version
Enter fullscreen mode Exit fullscreen mode

You should now have access to the deno desktop command.

Creating a Hello World Desktop App

Let’s create a minimal project.

mkdir deno-desktop-hello
cd deno-desktop-hello
touch main.ts
Enter fullscreen mode Exit fullscreen mode

Open main.ts and add the following code:

const html = `<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Hello Deno Desktop</title>
    <style>
      body {
        margin: 0;
        height: 100vh;
        display: grid;
        place-items: center;
        font-family: system-ui, sans-serif;
        background: #111827;
        color: white;
      }

      main {
        text-align: center;
      }

      h1 {
        font-size: 3rem;
        margin-bottom: 0.5rem;
      }

      p {
        color: #d1d5db;
        font-size: 1.1rem;
      }

      button {
        margin-top: 1rem;
        padding: 0.75rem 1rem;
        border: 0;
        border-radius: 0.5rem;
        cursor: pointer;
        font-size: 1rem;
      }
    </style>
  </head>
  <body>
    <main>
      <h1>Hello from Deno Desktop 👋</h1>
      <p>Your web app is now running inside a desktop window.</p>
      <button id="ping">Ping Deno</button>
      <p id="result"></p>
    </main>

    <script>
      const button = document.getElementById("ping");
      const result = document.getElementById("result");

      button.addEventListener("click", async () => {
        const response = await fetch("/api/hello");
        const data = await response.json();

        result.textContent = data.message;
      });
    </script>
  </body>
</html>`;

Deno.serve((request) => {
  const url = new URL(request.url);

  if (url.pathname === "/api/hello") {
    return Response.json({
      message: "Hello from the Deno backend!",
    });
  }

  return new Response(html, {
    headers: {
      "content-type": "text/html; charset=utf-8",
    },
  });
});
Enter fullscreen mode Exit fullscreen mode

This is just a normal Deno HTTP server.

The interesting part is that, when we run it with deno desktop, Deno will serve this app locally and open it in a desktop window.

Running the App

Run the app with:

deno desktop main.ts
Enter fullscreen mode Exit fullscreen mode

You should see a desktop window with:

Hello from Deno Desktop 👋
Enter fullscreen mode Exit fullscreen mode

Click the button, and the frontend will call the local API route:

/api/hello
Enter fullscreen mode Exit fullscreen mode

The Deno backend responds with JSON:

{
  "message": "Hello from the Deno backend!"
}
Enter fullscreen mode Exit fullscreen mode

And the UI displays the response.

Congratulations — you just built your first Deno desktop app.


What Is Happening Here?

The architecture is simple:

Desktop window
      ↓
Local webview
      ↓
Deno.serve()
      ↓
HTML + API routes
Enter fullscreen mode Exit fullscreen mode

Your app is still written like a web app, but it runs inside a desktop shell.

This has a few benefits:

  • You can use standard browser APIs in the UI.
  • You can use Deno APIs on the backend side.
  • You can build with TypeScript out of the box.
  • You can reuse patterns you already know from web development.
  • You can later move to a framework like Fresh, Astro, Next.js, or another supported stack.

Adding a Basic deno.json

You can also add a deno.json file to configure your project:

{
  "name": "deno-desktop-hello",
  "version": "0.1.0",
  "tasks": {
    "desktop": "deno desktop main.ts"
  },
  "desktop": {
    "app": {
      "name": "Deno Desktop Hello",
      "identifier": "com.example.deno-desktop-hello"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Now you can run:

deno task desktop
Enter fullscreen mode Exit fullscreen mode

This makes the project a bit cleaner and gives your app a name and identifier.

Why This Is Interesting

Deno Desktop is exciting because it reduces the gap between web apps and desktop apps.

If you already know JavaScript, TypeScript, HTML, and CSS, you can start building desktop software without learning a completely different stack.

It could be useful for:

  • internal tools
  • admin panels
  • developer tools
  • local-first apps
  • dashboards
  • small productivity apps
  • AI tools that need local filesystem or runtime access

It also fits nicely with Deno’s philosophy: modern tooling, TypeScript support, web standards, and a batteries-included developer experience.

Final Thoughts

Deno Desktop is still new, but the developer experience already feels very natural.

You write a Deno server.
You serve a UI.
You run deno desktop.
You get a desktop app.

For JavaScript and TypeScript developers, that is a very compelling workflow.

Here is the full minimal version again:

Deno.serve(() => {
  return new Response("<h1>Hello from Deno Desktop 👋</h1>", {
    headers: {
      "content-type": "text/html",
    },
  });
});
Enter fullscreen mode Exit fullscreen mode

Run it with:

deno desktop main.ts
Enter fullscreen mode Exit fullscreen mode

And that is your first Deno-powered desktop app.

Top comments (0)