From 43f4b9454c5e363d9631c04e7d2c311ef2d1c65a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 11 Jun 2026 20:56:20 +0200 Subject: [PATCH 1/6] docs: rewrite the web development guide --- runtime/fundamentals/web_dev.md | 233 ++++++++++++++++---------------- 1 file changed, 120 insertions(+), 113 deletions(-) diff --git a/runtime/fundamentals/web_dev.md b/runtime/fundamentals/web_dev.md index 2fa573057..702b9b7b8 100644 --- a/runtime/fundamentals/web_dev.md +++ b/runtime/fundamentals/web_dev.md @@ -1,119 +1,123 @@ --- -last_modified: 2025-10-10 title: "Web development" -description: "A guide to web development with Deno. Learn about supported frameworks like Fresh, Next.js, and Astro, along with built-in features for building modern web applications." +description: "Set up Fresh, Next.js, Astro, Vite, Lume, or Docusaurus with Deno, or build a server without a framework. Verified commands and Deno-specific notes." oldUrl: - /runtime/manual/getting_started/web_frameworks/ - /runtime/fundamentals/web_frameworks/ --- -Deno offers a secure and developer-friendly environment for building web -applications, making your web dev a delightful experience. +This page shows you how to start a web project with Deno, either with a popular +framework or with nothing but the built-in HTTP server. For each framework you +get the current scaffolding command, how to run the dev server, and what is +actually different when the project runs under Deno instead of Node.js. -1. Deno has [secure defaults](/runtime/fundamentals/security/), meaning it - requires explicit permission for file, network, and environment access, - reducing the risk of security vulnerabilities. -2. Deno has [built-in TypeScript support](/runtime/fundamentals/typescript/), - allowing you to write TypeScript code without additional configuration or - tooling. -3. Deno comes with a [standard library](/runtime/reference/std/) that includes - modules for common tasks like HTTP servers, file system operations, and more. +A note on permissions before you start: the scaffolding commands below use `-A` +(allow all permissions) because project generators genuinely need broad access. +They write files, read environment variables, and download and execute packages. +Servers you write yourself need far less, and the +[no-framework section](#without-a-framework) shows what minimal permissions look +like in practice. -For your vanilla TypeScript, or JavaScript, web applications, you can use the -built-in Deno [HTTP server](/runtime/fundamentals/http_server/). This is a great -way to get started with Deno and build simple web applications without any -additional dependencies. - -Most likely, if you're building a more complex application, you'll be -interacting with Deno through a web framework. - -## React/Next +## Fresh -[React](https://reactjs.org/) is a popular JavaScript library for building user -interfaces. To use React with Deno, you can use the popular web framework -[Next.js](https://nextjs.org/). +[Fresh](https://fresh.deno.dev/) is the web framework built for Deno. It renders +pages on the server and ships no JavaScript to the client by default. +Interactive components are opt-in +[islands](https://jasonformat.com/islands-architecture/), so you only pay for +client-side rendering where you ask for it. -To get started with Next.js in Deno, you can create a new next app and run it -immediately with Deno: +Create a project and start the dev server: ```sh -deno run -A npm:create-next-app@latest my-next-app -cd my-next-app +deno run -Ar jsr:@fresh/init +cd my-fresh-app deno task dev ``` -This will create a new Next.js app with TypeScript and run it with Deno. You can -then open your browser to `http://localhost:3000` to see your new app, and start -editing `page.tsx` to see your changes live. +The `-r` flag forces Deno to re-download the initializer so you always get the +latest version. The dev server prints its URL when it starts (Fresh 2 uses Vite +for development, which defaults to `http://localhost:5173`). Edit +`routes/index.tsx` to see changes live. -To better understand how JSX and Deno interface under the hood, read on -[here](/runtime/reference/jsx/). - -## Fresh +What's different under Deno: nothing to translate, because Fresh targets Deno +directly. Configuration lives in `deno.json` rather than `package.json`, +dependencies come from [JSR](https://jsr.io) and npm through the `imports` map, +and a `deno.lock` file pins them. The generated project sets +`"nodeModulesDir": "manual"` and the initializer creates a `node_modules` +directory, because the Vite-based dev server expects one. The generated tasks +already carry the permissions they need; for example the production `start` task +runs `deno serve -A _fresh/server.js`. -[Fresh](https://usefresh.dev/) is the most popular web framework for Deno. It -uses a model where you send no JavaScript to clients by default. +## Next.js -To get started with a Fresh app, you can use the following command and follow -the cli prompts to create your app: +[Next.js](https://nextjs.org/) is a React framework with file-system routing and +server-side rendering. It has no Deno integration of its own, but it runs under +Deno through [Node.js compatibility](/runtime/fundamentals/node/). ```sh -deno run -Ar jsr:@fresh/init -cd my-fresh-app +deno run -A npm:create-next-app@latest my-next-app +cd my-next-app +deno install deno task dev ``` -This will create a new Fresh app and run it with Deno. You can then open your -browser to `http://localhost:8000` to see your new app. Edit `/routes/index.tsx` -to see your changes live. +Open `http://localhost:3000` and edit `app/page.tsx` to see changes live. -Fresh does the majority of its rendering on the server, and the client is only -responsible for re-rendering small -[islands of interactivity](https://jasonformat.com/islands-architecture/). This -means the developer explicitly opts in to client side rendering for specific -components. +What's different under Deno: the scaffold is a standard npm project with a +`package.json`. When a `package.json` is present, Deno expects a local +`node_modules` directory, which is why `deno install` runs before the dev +server. Deno records resolved versions in `deno.lock`. `deno task dev` runs the +`dev` script from `package.json`, exactly like `npm run dev` would. To +understand how Deno handles JSX in general, see the +[JSX reference](/runtime/reference/jsx/). ## Astro -[Astro](https://astro.build/) is a static site generator that allows developers -to create fast and lightweight websites. - -To get started with Astro, you can use the following command to create a new -Astro site: +[Astro](https://astro.build/) is a content-focused framework that ships static +HTML by default and hydrates components only where needed. ```sh -deno run -A npm:create-astro my-astro-site +deno run -A npm:create-astro@latest cd my-astro-site +deno install deno task dev ``` -This will create a new Astro site and run it with Deno. You can then open your -browser to `http://localhost:4321` to see your new site. Edit -`/src/pages/index.astro` to see your changes live. +Open `http://localhost:4321` and edit `src/pages/index.astro` to see changes +live. -## Vite +What's different under Deno: the same story as Next.js. Astro is an npm project +built on Vite, so it needs `node_modules`, which `deno install` creates. Beyond +that there is no Deno-specific configuration. If the setup wizard offers to +install dependencies for you, you can skip that step and let `deno install` +handle it. -[Vite](https://vitejs.dev/) is a web dev build tool that serves your code via -native ES modules, which can be run directly in the browser. Vite is a great -choice for building modern web applications with Deno. +## Vite -To get started with Vite, you can use the following command to create a new Vite -app: +[Vite](https://vite.dev/) is a build tool and dev server used standalone or +underneath frameworks like Vue, React, and Svelte. Vite's own documentation +includes a Deno-specific scaffolding command: ```sh -deno run -A npm:create-vite@latest +deno init --npm vite my-vite-app cd my-vite-app deno install deno task dev ``` -## Lume +You can pick a template directly, for example +`deno init --npm vite my-vite-app --template react-ts`. The dev server runs at +`http://localhost:5173`. -[Lume](https://lume.land/) is a static site generator for Deno that is inspired -by other static site generators such Jekyll or Eleventy. +What's different under Deno: `deno init --npm vite` runs the `create-vite` +generator for you. The result is an npm project with a `package.json`, so +`deno install` creates the `node_modules` directory Vite requires. From there, +everything works as it would under Node.js. -To get started with Lume, you can use the following command to create a new Lume -site: +## Lume + +[Lume](https://lume.land/) is a static site generator built for Deno, inspired +by Jekyll and Eleventy. ```sh mkdir my-lume-site @@ -122,13 +126,17 @@ deno run -A https://lume.land/init.ts deno task serve ``` -## Docusaurus +The `serve` task builds the site, starts a local server at +`http://localhost:3000`, and rebuilds on changes. -[Docusaurus](https://docusaurus.io/) is a static site generator that is -optimized for technical documentation websites. +What's different under Deno: like Fresh, Lume is Deno-native. There is no +`package.json` and no `node_modules`. The site is configured in `_config.ts`, +tasks live in `deno.json`, and plugins are imported as modules. -To get started with Docusaurus, you can use the following command to create a -new Docusaurus site: +## Docusaurus + +[Docusaurus](https://docusaurus.io/) is a static site generator optimized for +documentation websites. ```sh deno run -A npm:create-docusaurus@latest my-website classic @@ -136,67 +144,66 @@ cd my-website deno task start ``` -## Hono +Open `http://localhost:3000` to see the site. + +What's different under Deno: nothing. Docusaurus is a plain npm project that +runs through Deno's Node.js compatibility unchanged. + +## Without a framework -[Hono](https://hono.dev) is a light-weight web app framework in the tradition of -Express and Sinatra. +Deno ships an HTTP server in the runtime, so for APIs, webhooks, and small sites +you may not need a framework at all. The +[HTTP server guide](/runtime/fundamentals/http_server/) covers serving requests, +routing by URL, streaming, and WebSockets with zero dependencies. -To get started with Hono, you can use the following command to create a new Hono -app: +When you outgrow hand-rolled routing, two lightweight options work well with +Deno: + +[Hono](https://hono.dev/) is a small, fast router in the tradition of Express, +with first-class Deno support: ```sh -deno run -A npm:create-hono@latest +deno init --npm hono --template=deno my-hono-app cd my-hono-app deno task start ``` -This will create a new Hono app and run it with Deno. You can then open your -browser to `http://localhost:8000` to see your new app. - -## Oak - -[Oak](https://jsr.io/@oak/oak) is a middleware framework for handling HTTP with -Deno. Oak is the glue between your frontend application and a potential database -or other data sources (e.g. REST APIs, GraphQL APIs). - -Oak offers additional functionality over the native Deno HTTP server, including -a basic router, JSON parser, middlewares, plugins, etc. - -To get started with Oak, make a file called `server.ts` and add the following: +[Oak](https://jsr.io/@oak/oak) is a middleware framework in the tradition of +Koa, published on JSR. Add it with `deno add jsr:@oak/oak`, then create +`server.ts`: ```ts -import { Application } from "jsr:@oak/oak/application"; -import { Router } from "jsr:@oak/oak/router"; +import { Application, Router } from "@oak/oak"; const router = new Router(); router.get("/", (ctx) => { - ctx.response.body = ` - - Hello oak! - -

Hello oak!

- - - `; + ctx.response.body = "Hello Oak!"; }); const app = new Application(); -const port = 8080; - app.use(router.routes()); app.use(router.allowedMethods()); -console.log(`Server running on http://localhost:${port}`); - -app.listen({ port: port }); +app.listen({ port: 8000 }); ``` -Run the server with the following command: +Servers like these are where Deno's +[permission model](/runtime/fundamentals/security/) pays off. Unlike the +scaffolding tools above, a basic server only needs network access: ```sh deno run --allow-net server.ts ``` -## Node projects +If your server later reads files or environment variables, add `--allow-read` or +`--allow-env` for exactly what it touches instead of reaching for `-A`. + +## Keep going -Deno will run your Node.js projects out the box. Check out our guide on -[migrating your Node.js project to Deno](/runtime/migrate/). +- Build a server from scratch in the + [HTTP server guide](/runtime/fundamentals/http_server/). +- See which browser-standard APIs (`fetch`, Web Streams, Web Crypto, and more) + are available in the + [web platform APIs reference](/runtime/reference/web_platform_apis/). +- Follow step-by-step framework tutorials, including React, Vue, SolidJS, and + more, in the [examples and tutorials section](/examples/). +- When your app is ready for production, deploy it with [Deno Deploy](/deploy/). From f28fa95a860f44eed1cb4dac4f2c254a1d756a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 12 Jun 2026 13:35:37 +0200 Subject: [PATCH 2/6] docs: review fixes for the web dev rewrite Restore last_modified (the site renders it as the visible last-updated date), pass the project name to create-astro so the cd that follows is guaranteed to match, and add a deno install step to the Docusaurus section so the scaffold works on machines without npm. --- runtime/fundamentals/web_dev.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/runtime/fundamentals/web_dev.md b/runtime/fundamentals/web_dev.md index 702b9b7b8..e7f2fd6ba 100644 --- a/runtime/fundamentals/web_dev.md +++ b/runtime/fundamentals/web_dev.md @@ -1,4 +1,5 @@ --- +last_modified: 2026-06-12 title: "Web development" description: "Set up Fresh, Next.js, Astro, Vite, Lume, or Docusaurus with Deno, or build a server without a framework. Verified commands and Deno-specific notes." oldUrl: @@ -77,7 +78,7 @@ understand how Deno handles JSX in general, see the HTML by default and hydrates components only where needed. ```sh -deno run -A npm:create-astro@latest +deno run -A npm:create-astro@latest my-astro-site cd my-astro-site deno install deno task dev @@ -141,13 +142,15 @@ documentation websites. ```sh deno run -A npm:create-docusaurus@latest my-website classic cd my-website +deno install deno task start ``` Open `http://localhost:3000` to see the site. -What's different under Deno: nothing. Docusaurus is a plain npm project that -runs through Deno's Node.js compatibility unchanged. +What's different under Deno: almost nothing. Docusaurus is a plain npm project +that runs through Deno's Node.js compatibility unchanged; `deno install` puts +the `node_modules` directory in place, the same as for Next.js and Astro. ## Without a framework From c4041fffaa60fa9330d4f9b4075b0e1087567b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 12 Jun 2026 14:36:58 +0200 Subject: [PATCH 3/6] docs: make Fresh and Docusaurus scaffold commands copy-pasteable Pass the directory to @fresh/init so the cd that follows matches (same fix as Astro), and add --skip-install to create-docusaurus so the generator does not invoke npm itself; deno install handles it. --- runtime/fundamentals/web_dev.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/runtime/fundamentals/web_dev.md b/runtime/fundamentals/web_dev.md index e7f2fd6ba..68a6a60e6 100644 --- a/runtime/fundamentals/web_dev.md +++ b/runtime/fundamentals/web_dev.md @@ -30,7 +30,7 @@ client-side rendering where you ask for it. Create a project and start the dev server: ```sh -deno run -Ar jsr:@fresh/init +deno run -Ar jsr:@fresh/init my-fresh-app cd my-fresh-app deno task dev ``` @@ -140,7 +140,7 @@ tasks live in `deno.json`, and plugins are imported as modules. documentation websites. ```sh -deno run -A npm:create-docusaurus@latest my-website classic +deno run -A npm:create-docusaurus@latest my-website classic --skip-install cd my-website deno install deno task start @@ -149,8 +149,9 @@ deno task start Open `http://localhost:3000` to see the site. What's different under Deno: almost nothing. Docusaurus is a plain npm project -that runs through Deno's Node.js compatibility unchanged; `deno install` puts -the `node_modules` directory in place, the same as for Next.js and Astro. +that runs through Deno's Node.js compatibility unchanged. The `--skip-install` +flag stops the generator from invoking npm, and `deno install` puts the +`node_modules` directory in place instead, the same as for Next.js and Astro. ## Without a framework From 3506c9c3d62064207c54b01f6681ecb0666cdcdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 12 Jun 2026 14:37:41 +0200 Subject: [PATCH 4/6] docs: await app.listen in the Oak example --- runtime/fundamentals/web_dev.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/fundamentals/web_dev.md b/runtime/fundamentals/web_dev.md index 68a6a60e6..0ef16caac 100644 --- a/runtime/fundamentals/web_dev.md +++ b/runtime/fundamentals/web_dev.md @@ -187,7 +187,7 @@ router.get("/", (ctx) => { const app = new Application(); app.use(router.routes()); app.use(router.allowedMethods()); -app.listen({ port: 8000 }); +await app.listen({ port: 8000 }); ``` Servers like these are where Deno's From 5ec26586e2932ea965510979941ae99a2e4e3790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 15 Jun 2026 16:44:22 +0200 Subject: [PATCH 5/6] docs: reshape the web development guide into a real guide The page was a scaffolding catalog: six framework sections, four of them the same 'it's an npm project, run deno install' paragraph, with all the actual web-development content linked out to other pages. Give it a spine instead. Lead with a decision table (no framework / Deno-native / npm) so readers can self-route. Add a 'start without a framework' section with a real, verified ~20-line server (HTML page, JSON route, static files) that earns the page's title, then points to the HTTP server guide for depth. Keep Fresh and Lume as full Deno-native sections. Collapse the four near-identical npm-framework sections into one shared 'how npm frameworks work under Deno' explanation plus a verified-command table, which also lets the table cover SvelteKit and Nuxt (both newly verified to scaffold and run under Deno) without adding bulk. --- runtime/fundamentals/web_dev.md | 286 +++++++++++++++++--------------- 1 file changed, 148 insertions(+), 138 deletions(-) diff --git a/runtime/fundamentals/web_dev.md b/runtime/fundamentals/web_dev.md index 0ef16caac..cdea586ef 100644 --- a/runtime/fundamentals/web_dev.md +++ b/runtime/fundamentals/web_dev.md @@ -1,121 +1,146 @@ --- -last_modified: 2026-06-12 +last_modified: 2026-06-15 title: "Web development" -description: "Set up Fresh, Next.js, Astro, Vite, Lume, or Docusaurus with Deno, or build a server without a framework. Verified commands and Deno-specific notes." +description: "Build for the web with Deno: start with the built-in HTTP server, choose a Deno-native or npm framework, and run each one with verified commands and Deno-specific notes." oldUrl: - /runtime/manual/getting_started/web_frameworks/ - /runtime/fundamentals/web_frameworks/ --- -This page shows you how to start a web project with Deno, either with a popular -framework or with nothing but the built-in HTTP server. For each framework you -get the current scaffolding command, how to run the dev server, and what is -actually different when the project runs under Deno instead of Node.js. +There are three ways to build for the web with Deno, and this page covers all of +them: start from the built-in HTTP server with no dependencies, reach for a +Deno-native framework, or run an established npm framework through Deno's +Node.js compatibility. Pick the row that matches what you're building: -A note on permissions before you start: the scaffolding commands below use `-A` -(allow all permissions) because project generators genuinely need broad access. -They write files, read environment variables, and download and execute packages. -Servers you write yourself need far less, and the -[no-framework section](#without-a-framework) shows what minimal permissions look -like in practice. +| Approach | Reach for it when | Covered below | +| --------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------- | +| **No framework** | APIs, webhooks, small sites; you want minimal dependencies | [Start without a framework](#start-without-a-framework) | +| **A Deno-native framework** | You want the smoothest Deno experience, no Node compatibility layer | [Deno-native frameworks](#deno-native-frameworks) | +| **An npm framework** | You want an established React, Vue, or Svelte ecosystem framework | [Run an npm framework](#run-an-npm-framework) | -## Fresh +## Start without a framework -[Fresh](https://fresh.deno.dev/) is the web framework built for Deno. It renders -pages on the server and ships no JavaScript to the client by default. -Interactive components are opt-in -[islands](https://jasonformat.com/islands-architecture/), so you only pay for -client-side rendering where you ask for it. +Deno ships an HTTP server in the runtime, so for APIs, webhooks, and small sites +you may not need a framework at all. `Deno.serve` takes a handler that receives +a standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) +and returns a +[`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), the +same objects you already know from the browser. Here is a server that returns an +HTML page, a JSON API route, and a static file: + +```ts title="server.ts" +import { serveDir } from "jsr:@std/http/file-server"; + +Deno.serve((req) => { + const { pathname } = new URL(req.url); + + // A JSON API route + if (pathname === "/api/hello") { + return Response.json({ message: "Hello from Deno" }); + } + + // Static assets from ./public, served under /static/ + if (pathname.startsWith("/static/")) { + return serveDir(req, { fsRoot: "public", urlRoot: "static" }); + } + + // Everything else: an HTML page + return new Response( + ` + +

Hello from Deno

+

Try /api/hello

`, + { headers: { "content-type": "text/html; charset=utf-8" } }, + ); +}); +``` -Create a project and start the dev server: +This is where Deno's [permission model](/runtime/fundamentals/security/) pays +off: a server you write yourself asks for exactly what it touches. This one +needs network access to listen and read access to serve files from `public/`, +and nothing more: ```sh -deno run -Ar jsr:@fresh/init my-fresh-app -cd my-fresh-app -deno task dev +deno run --allow-net --allow-read server.ts ``` -The `-r` flag forces Deno to re-download the initializer so you always get the -latest version. The dev server prints its URL when it starts (Fresh 2 uses Vite -for development, which defaults to `http://localhost:5173`). Edit -`routes/index.tsx` to see changes live. +The [HTTP server guide](/runtime/fundamentals/http_server/) takes this further: +routing, streaming responses, graceful shutdown, HTTPS, HTTP/2, and WebSockets, +all with zero dependencies. -What's different under Deno: nothing to translate, because Fresh targets Deno -directly. Configuration lives in `deno.json` rather than `package.json`, -dependencies come from [JSR](https://jsr.io) and npm through the `imports` map, -and a `deno.lock` file pins them. The generated project sets -`"nodeModulesDir": "manual"` and the initializer creates a `node_modules` -directory, because the Vite-based dev server expects one. The generated tasks -already carry the permissions they need; for example the production `start` task -runs `deno serve -A _fresh/server.js`. +### Lightweight routers -## Next.js +When you outgrow hand-rolled routing but don't want a full framework, two small +libraries work well with Deno. -[Next.js](https://nextjs.org/) is a React framework with file-system routing and -server-side rendering. It has no Deno integration of its own, but it runs under -Deno through [Node.js compatibility](/runtime/fundamentals/node/). +[Hono](https://hono.dev/) is a small, fast router in the tradition of Express, +with first-class Deno support: ```sh -deno run -A npm:create-next-app@latest my-next-app -cd my-next-app -deno install -deno task dev +deno init --npm hono --template=deno my-hono-app +cd my-hono-app +deno task start ``` -Open `http://localhost:3000` and edit `app/page.tsx` to see changes live. +[Oak](https://jsr.io/@oak/oak) is a middleware framework in the tradition of +Koa, published on JSR. Add it with `deno add jsr:@oak/oak`, then create +`server.ts`: -What's different under Deno: the scaffold is a standard npm project with a -`package.json`. When a `package.json` is present, Deno expects a local -`node_modules` directory, which is why `deno install` runs before the dev -server. Deno records resolved versions in `deno.lock`. `deno task dev` runs the -`dev` script from `package.json`, exactly like `npm run dev` would. To -understand how Deno handles JSX in general, see the -[JSX reference](/runtime/reference/jsx/). +```ts title="server.ts" +import { Application, Router } from "@oak/oak"; + +const router = new Router(); +router.get("/", (ctx) => { + ctx.response.body = "Hello Oak!"; +}); -## Astro +const app = new Application(); +app.use(router.routes()); +app.use(router.allowedMethods()); +await app.listen({ port: 8000 }); +``` -[Astro](https://astro.build/) is a content-focused framework that ships static -HTML by default and hydrates components only where needed. +Run it the same way, granting only network access: ```sh -deno run -A npm:create-astro@latest my-astro-site -cd my-astro-site -deno install -deno task dev +deno run --allow-net server.ts ``` -Open `http://localhost:4321` and edit `src/pages/index.astro` to see changes -live. +## Deno-native frameworks + +These frameworks target Deno directly. There is no `package.json` to translate +and no Node.js compatibility layer in the way: configuration lives in +`deno.json`, dependencies come from [JSR](https://jsr.io) and npm through the +`imports` map, and a `deno.lock` file pins them. -What's different under Deno: the same story as Next.js. Astro is an npm project -built on Vite, so it needs `node_modules`, which `deno install` creates. Beyond -that there is no Deno-specific configuration. If the setup wizard offers to -install dependencies for you, you can skip that step and let `deno install` -handle it. +### Fresh -## Vite +[Fresh](https://fresh.deno.dev/) is the web framework built for Deno. It renders +pages on the server and ships no JavaScript to the client by default. +Interactive components are opt-in +[islands](https://jasonformat.com/islands-architecture/), so you only pay for +client-side rendering where you ask for it. -[Vite](https://vite.dev/) is a build tool and dev server used standalone or -underneath frameworks like Vue, React, and Svelte. Vite's own documentation -includes a Deno-specific scaffolding command: +Create a project and start the dev server: ```sh -deno init --npm vite my-vite-app -cd my-vite-app -deno install +deno run -Ar jsr:@fresh/init my-fresh-app +cd my-fresh-app deno task dev ``` -You can pick a template directly, for example -`deno init --npm vite my-vite-app --template react-ts`. The dev server runs at -`http://localhost:5173`. +The `-r` flag forces Deno to re-download the initializer so you always get the +latest version. The dev server prints its URL when it starts (Fresh 2 uses Vite +for development, which defaults to `http://localhost:5173`). Edit +`routes/index.tsx` to see changes live. -What's different under Deno: `deno init --npm vite` runs the `create-vite` -generator for you. The result is an npm project with a `package.json`, so -`deno install` creates the `node_modules` directory Vite requires. From there, -everything works as it would under Node.js. +What's different under Deno: nothing to translate, because Fresh targets Deno +directly. The generated project sets `"nodeModulesDir": "manual"` and the +initializer creates a `node_modules` directory, because the Vite-based dev +server expects one. The generated tasks already carry the permissions they need; +for example the production `start` task runs `deno serve -A _fresh/server.js`. -## Lume +### Lume [Lume](https://lume.land/) is a static site generator built for Deno, inspired by Jekyll and Eleventy. @@ -134,72 +159,57 @@ What's different under Deno: like Fresh, Lume is Deno-native. There is no `package.json` and no `node_modules`. The site is configured in `_config.ts`, tasks live in `deno.json`, and plugins are imported as modules. -## Docusaurus - -[Docusaurus](https://docusaurus.io/) is a static site generator optimized for -documentation websites. - -```sh -deno run -A npm:create-docusaurus@latest my-website classic --skip-install -cd my-website -deno install -deno task start -``` - -Open `http://localhost:3000` to see the site. - -What's different under Deno: almost nothing. Docusaurus is a plain npm project -that runs through Deno's Node.js compatibility unchanged. The `--skip-install` -flag stops the generator from invoking npm, and `deno install` puts the -`node_modules` directory in place instead, the same as for Next.js and Astro. - -## Without a framework - -Deno ships an HTTP server in the runtime, so for APIs, webhooks, and small sites -you may not need a framework at all. The -[HTTP server guide](/runtime/fundamentals/http_server/) covers serving requests, -routing by URL, streaming, and WebSockets with zero dependencies. - -When you outgrow hand-rolled routing, two lightweight options work well with -Deno: - -[Hono](https://hono.dev/) is a small, fast router in the tradition of Express, -with first-class Deno support: - -```sh -deno init --npm hono --template=deno my-hono-app -cd my-hono-app -deno task start -``` - -[Oak](https://jsr.io/@oak/oak) is a middleware framework in the tradition of -Koa, published on JSR. Add it with `deno add jsr:@oak/oak`, then create -`server.ts`: +## Run an npm framework -```ts -import { Application, Router } from "@oak/oak"; - -const router = new Router(); -router.get("/", (ctx) => { - ctx.response.body = "Hello Oak!"; -}); +Established npm frameworks run under Deno through +[Node.js compatibility](/runtime/fundamentals/node/), and the pattern is the +same for all of them: -const app = new Application(); -app.use(router.routes()); -app.use(router.allowedMethods()); -await app.listen({ port: 8000 }); -``` +1. **Scaffold** with the framework's own generator, run through Deno. Generators + need `-A` (allow all) because they write files, read environment variables, + and download and execute packages. +2. **Install** with `deno install`. The scaffold is a standard npm project with + a `package.json`, and Deno expects a local `node_modules` directory when one + is present. This step creates it and records resolved versions in + `deno.lock`. +3. **Run** the dev server with `deno task`, which executes the scripts from + `package.json` exactly as `npm run` would. -Servers like these are where Deno's -[permission model](/runtime/fundamentals/security/) pays off. Unlike the -scaffolding tools above, a basic server only needs network access: +So a full setup looks like: ```sh -deno run --allow-net server.ts +deno run -A npm:create-next-app@latest my-app +cd my-app +deno install +deno task dev ``` -If your server later reads files or environment variables, add `--allow-read` or -`--allow-env` for exactly what it touches instead of reaching for `-A`. +The scaffold command and dev server differ per framework. These are all verified +to run under Deno: + +| Framework | Scaffold command | Start dev server | +| ------------------------------------ | --------------------------------------------------------- | --------------------------- | +| [Next.js](https://nextjs.org/) | `deno run -A npm:create-next-app@latest my-app` | `deno task dev` → `:3000` | +| [Astro](https://astro.build/) | `deno run -A npm:create-astro@latest my-app` | `deno task dev` → `:4321` | +| [Vite](https://vite.dev/) | `deno init --npm vite my-app` | `deno task dev` → `:5173` | +| [SvelteKit](https://svelte.dev/) | `deno run -A npm:sv create my-app` | `deno task dev` → `:5173` | +| [Nuxt](https://nuxt.com/) | `deno run -A npm:create-nuxt@latest my-app` | `deno task dev` → `:3000` | +| [Docusaurus](https://docusaurus.io/) | `deno run -A npm:create-docusaurus@latest my-app classic` | `deno task start` → `:3000` | + +A few per-framework notes: + +- **Vite** can take a template directly, for example + `deno init --npm vite my-app --template react-ts`. `deno init --npm vite` runs + the `create-vite` generator for you. +- **SvelteKit** and **Nuxt** generators are interactive: they prompt for a + template and options, and both already list Deno as a package manager. +- **Astro**'s setup wizard may offer to install dependencies for you; skip that + and let `deno install` handle it. +- **Docusaurus** also accepts `--skip-install` to stop the generator from + invoking npm, leaving the install to `deno install`. + +To understand how Deno handles JSX in any of these, see the +[JSX reference](/runtime/reference/jsx/). ## Keep going From f0fb9abd842f3059db1fe1a103867373e856a34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 15 Jun 2026 17:09:49 +0200 Subject: [PATCH 6/6] docs: link the Deno.serve API reference --- runtime/fundamentals/web_dev.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/runtime/fundamentals/web_dev.md b/runtime/fundamentals/web_dev.md index cdea586ef..dedc75223 100644 --- a/runtime/fundamentals/web_dev.md +++ b/runtime/fundamentals/web_dev.md @@ -21,9 +21,10 @@ Node.js compatibility. Pick the row that matches what you're building: ## Start without a framework Deno ships an HTTP server in the runtime, so for APIs, webhooks, and small sites -you may not need a framework at all. `Deno.serve` takes a handler that receives -a standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) -and returns a +you may not need a framework at all. [`Deno.serve`](/api/deno/~/Deno.serve) +takes a handler that receives a standard +[`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) and +returns a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), the same objects you already know from the browser. Here is a server that returns an HTML page, a JSON API route, and a static file: