Skip to content
Merged
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
c47329e
docs: remove TODO placeholders and fill in missing content
bartlomieju Mar 27, 2026
daead8b
docs: fix broken code examples
bartlomieju Mar 27, 2026
f1fe5fa
docs: fix copy-pasted frontmatter descriptions
bartlomieju Mar 27, 2026
1b22639
docs: fix CSRF page using CORS description
bartlomieju Mar 27, 2026
1fbed75
docs: fix grammar errors and typos across documentation
bartlomieju Mar 27, 2026
066622c
docs: add navigation links to advanced index page
bartlomieju Mar 27, 2026
d08b293
docs: expand routing page with priority, methods, and file handlers
bartlomieju Mar 27, 2026
12931a1
docs: expand Vite plugin page with HMR, plugin composition, and inter…
bartlomieju Mar 27, 2026
36d3d2f
docs: add Signals concept page
bartlomieju Mar 27, 2026
be611a3
docs: add API Routes example page
bartlomieju Mar 27, 2026
04aceb6
docs: cross-link the two Layouts pages
bartlomieju Mar 27, 2026
ecb7205
docs: resolve contradictory build commands in deployment page
bartlomieju Mar 27, 2026
8731665
docs: expand Deno Deploy and deno compile deployment pages
bartlomieju Mar 27, 2026
6398da6
docs: add Data Fetching concept page
bartlomieju Mar 27, 2026
40e1b47
docs: add Serialization reference page
bartlomieju Mar 27, 2026
7b69ec6
docs: add Common Patterns recipes page
bartlomieju Mar 27, 2026
00a6228
docs: add Architecture overview with request lifecycle diagram
bartlomieju Mar 27, 2026
b13260d
docs: fix remaining code and content errors
bartlomieju Mar 27, 2026
033022a
docs: update concepts index with all sub-pages
bartlomieju Mar 27, 2026
b3d32a2
docs: add next steps section to getting started page
bartlomieju Mar 27, 2026
a651250
docs: explain (_islands) and (_components) directories in file routing
bartlomieju Mar 27, 2026
ff62595
docs: document previously undocumented features
bartlomieju Mar 27, 2026
5a035f9
docs: add API Reference page listing all public exports
bartlomieju Mar 27, 2026
ebf194e
docs: update examples index and fix migration guide grammar
bartlomieju Mar 27, 2026
025b3c6
fmt
bartlomieju Mar 28, 2026
5b8af4c
docs: add Deno version requirements to introduction
bartlomieju Mar 28, 2026
37aaaed
docs: add plugin authoring guidance to plugins page
bartlomieju Mar 28, 2026
272342a
docs: add OpenTelemetry page
bartlomieju Mar 28, 2026
3adb4cc
docs: add PR guidelines to contributing page
bartlomieju Mar 28, 2026
715a0fe
docs: document route css option in file routing
bartlomieju Mar 28, 2026
68bc424
docs: fix broken image references
bartlomieju Mar 28, 2026
8f16110
ci: add doc image reference checker test
bartlomieju Mar 28, 2026
2c0491e
chore: format check_images_test.ts
bartlomieju Mar 28, 2026
5dcb621
Merge branch 'main' into docs/quick-wins-audit-fixes
bartlomieju Mar 28, 2026
971ece9
fmt
bartlomieju Mar 28, 2026
542a082
docs: add layout overriding and multiple layouts to programmatic layouts
bartlomieju Mar 28, 2026
09d1332
docs: clarify .listen() behavior with default project setup
bartlomieju Mar 28, 2026
fd43eed
docs: fix Docker deployment instructions for Fresh 2
bartlomieju Mar 28, 2026
dc56896
docs: add tip about using root-relative URLs for static files
bartlomieju Mar 28, 2026
7e9bff1
docs: clarify main.ts vs main.tsx usage
bartlomieju Mar 28, 2026
7ec338c
docs: add catch-all redirect from /docs/canary/ to /docs/
bartlomieju Mar 28, 2026
3ac8461
docs: add progressive complexity code examples to homepage
bartlomieju Mar 28, 2026
60502ed
docs: clarify Head component dedup precedence order
bartlomieju Mar 28, 2026
6e1f660
docs: add custom elements (web components) section to islands docs
bartlomieju Mar 28, 2026
badf670
fix: redirect direct access to recipe partial routes to homepage
bartlomieju Mar 28, 2026
0c74c35
docs: rewrite cart example to avoid shared module-level signals
bartlomieju Mar 28, 2026
1b9e184
docs: add image optimization section to static files docs
bartlomieju Mar 28, 2026
a00673e
docs: add subdomain routing, proxying, and lazy island patterns
bartlomieju Mar 28, 2026
0e07166
chore: format docs
bartlomieju Mar 28, 2026
cfad1d8
fix: use page() instead of ctx.render() in recipe partial routes
bartlomieju Mar 28, 2026
80ba463
fix: add concepts/layouts to TOC and exclude GitHub edit links from c…
bartlomieju Mar 28, 2026
394441f
docs: fix code examples and docs from review feedback
bartlomieju Mar 28, 2026
92f0744
docs: fix remaining review issues
bartlomieju Mar 28, 2026
cb01272
docs: link to JSR auto-generated API docs
bartlomieju Mar 28, 2026
1614706
docs: replace ASCII art with HTML/CSS flowchart in architecture page
bartlomieju Mar 28, 2026
6a1b507
docs: replace em dashes, add cross-links, update introduction and arc…
bartlomieju Mar 28, 2026
4af0d2c
docs: update init command to use deno create
bartlomieju Mar 29, 2026
b560aa8
fmt
bartlomieju Mar 29, 2026
e136a75
reset CI
bartlomieju Mar 29, 2026
d91adac
fix link
bartlomieju Mar 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/1.x/concepts/partials.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Let's use a typical documentation page layout as an example. It often features a
main content area and a sidebar of links to switch between pages of the
documentation (marked green here).

![A sketched layout of a typical documentation page with the sidebar on the left composed of green links and a main content area on the right. The main content area is labeled as Partial docs-content](/docs/1.x/fresh-partial-docs.png)
![A sketched layout of a typical documentation page with the sidebar on the left composed of green links and a main content area on the right. The main content area is labeled as Partial docs-content](/docs/fresh-partial-docs.png)

The code for such a page (excluding styling) might look like this:

Expand Down
55 changes: 55 additions & 0 deletions docs/check_images_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Verifies that all image references in documentation markdown files
* point to existing files in www/static/.
*
* Run: deno test -A docs/check_images_test.ts
*/
import { walk } from "jsr:@std/fs@1/walk";
import { join, resolve } from "jsr:@std/path@1";

const ROOT = resolve(import.meta.dirname!);
const PROJECT_ROOT = resolve(ROOT, "..");
const DOCS_DIR = ROOT;
const STATIC_DIR = join(PROJECT_ROOT, "www", "static");

const IMAGE_RE = /!\[.*?\]\(([^)]+)\)/g;

Deno.test("all doc image references point to existing files", async () => {
const errors: string[] = [];

for await (
const entry of walk(DOCS_DIR, {
exts: [".md", ".mdx"],
includeDirs: false,
})
) {
const content = await Deno.readTextFile(entry.path);
const relativePath = entry.path.slice(PROJECT_ROOT.length);

for (const match of content.matchAll(IMAGE_RE)) {
const imgPath = match[1];

// Skip external URLs
if (imgPath.startsWith("http://") || imgPath.startsWith("https://")) {
continue;
}

// Doc image paths like "/docs/foo.png" map to "www/static/docs/foo.png"
const fsPath = join(STATIC_DIR, imgPath);

try {
await Deno.stat(fsPath);
} catch {
errors.push(`${relativePath}: image not found: ${imgPath}`);
}
}
}

if (errors.length > 0) {
throw new Error(
`Found ${errors.length} broken image reference(s):\n\n${
errors.join("\n")
}`,
);
}
});
98 changes: 98 additions & 0 deletions docs/latest/advanced/api-reference.md
Comment thread
bartlomieju marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
description: |
Quick reference for all public exports from Fresh's entry points: fresh, fresh/runtime, and fresh/dev.
---

This page lists all public exports from Fresh's entry points.

> [info]: You can also explore Fresh's full API documentation on JSR:
> [`@fresh/core`](https://jsr.io/@fresh/core/doc)

## `fresh`

The main entry point for server-side code.

```ts
import { App, createDefine, HttpError, page, staticFiles } from "fresh";
```

| Export | Kind | Description |
| ----------------- | -------- | -------------------------------------------------------------------------------------------------- |
| `App` | Class | The main application class. See [App](/docs/concepts/app). |
| `staticFiles` | Function | Middleware for serving static files. See [Static Files](/docs/concepts/static-files). |
| `createDefine` | Function | Create type-safe `define.*` helpers. See [Define Helpers](/docs/advanced/define). |
| `page` | Function | Return data from a handler to a page component. See [Data Fetching](/docs/concepts/data-fetching). |
| `HttpError` | Class | Throw HTTP errors with status codes. See [Error Handling](/docs/advanced/error-handling). |
| `cors` | Function | CORS middleware. See [cors](/docs/plugins/cors). |
| `csrf` | Function | CSRF protection middleware. See [csrf](/docs/plugins/csrf). |
| `csp` | Function | Content Security Policy middleware. See [csp](/docs/plugins/csp). |
| `trailingSlashes` | Function | Trailing slash enforcement middleware. See [trailingSlashes](/docs/plugins/trailing-slashes). |

**Types:**

| Export | Description |
| ------------------------------------- | ------------------------------------------------------------------------------------ |
| `Context` / `FreshContext` | The request context passed to all middlewares and handlers. |
| `PageProps` | Props received by page components (includes `data`, `url`, `params`, `state`, etc.). |
| `Middleware` / `MiddlewareFn` | Middleware function type. |
| `HandlerFn` | Single handler function type. |
| `HandlerByMethod` | Object with per-method handler functions. |
| `RouteHandler` | Union of `HandlerFn` and `HandlerByMethod`. |
| `PageResponse` | Return type of `page()`. |
| `RouteConfig` | Route configuration (`routeOverride`, `skipInheritedLayouts`, etc.). |
| `LayoutConfig` | Layout configuration (`skipInheritedLayouts`, `skipAppWrapper`). |
| `Define` | Type of the object returned by `createDefine()`. |
| `FreshConfig` / `ResolvedFreshConfig` | App configuration types. |
| `ListenOptions` | Options for `app.listen()`. |
| `Island` | Island component type. |
| `Method` | HTTP method union type. |
| `RouteData` | Data type returned by route handlers via `page()`. |
| `Lazy` / `MaybeLazy` | Utility types for lazily-loaded routes and middleware. |
| `CORSOptions` | Options for `cors()`. |
| `CsrfOptions` | Options for `csrf()`. |
| `CSPOptions` | Options for `csp()`. |

## `fresh/runtime`

Shared runtime utilities for both server and client code. Safe to import in
islands.

```ts
import {
asset,
assetSrcSet,
Head,
HttpError,
IS_BROWSER,
Partial,
} from "fresh/runtime";
```

| Export | Kind | Description |
| ------------- | --------- | ---------------------------------------------------------------------------------------------- |
| `IS_BROWSER` | Constant | `true` in the browser, `false` on the server. Use to guard browser-only code. |
| `asset` | Function | Add cache-busting query params to asset URLs. See [Static Files](/docs/concepts/static-files). |
| `assetSrcSet` | Function | Apply `asset()` to all URLs in a `srcset` string. |
| `Partial` | Component | Mark a region for partial updates. See [Partials](/docs/advanced/partials). |
| `Head` | Component | Add elements to the document `<head>`. See [Modifying head](/docs/advanced/head). |
| `HttpError` | Class | HTTP error class (re-exported from `fresh`). |

@crowlKats crowlKats Mar 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just tested on JSR repo, this doesnt seem to be available in fresh/runtime?
Ideally it is (needed for making jsr-io/jsr#1352 landable)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's just not released yet: #3080

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be part of2.2.2 release... I'll check what's going on

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


## `fresh/dev`

Development and build tools. Only used in `dev.ts` (legacy) or build scripts.

```ts
import { Builder } from "fresh/dev";
```

| Export | Kind | Description |
| --------- | ----- | ---------------------------------------------------------------------- |
| `Builder` | Class | Pre-Vite build system (legacy). See [Builder](/docs/advanced/builder). |

**Types:**

| Export | Description |
| -------------------------------------------------------- | ----------------------------- |
| `BuildOptions` | Options for `new Builder()`. |
| `ResolvedBuildConfig` | Resolved build configuration. |
| `OnTransformArgs` / `OnTransformOptions` / `TransformFn` | Build plugin hook types. |
4 changes: 2 additions & 2 deletions docs/latest/advanced/builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ For more information on how to use tailwindcss, check out
You can customize the tailwind plugin via the following options:

```ts dev.ts
tailwind(builder, app, {
tailwind(builder, {
// Exclude certain files from processing
exclude: ["/admin/**", "*.temp.css"],
// Force optimization (defaults to production mode)
Expand All @@ -183,7 +183,7 @@ tailwind(builder, app, {

### Tailwindcss v3

If can't update to the current version of tailwindcss we have a dedicated
If you can't update to the current version of tailwindcss we have a dedicated
`@fresh/plugin-tailwindcss-v3` plugin that uses tailwindcss v3. That way you can
decided on your own when it's best to update to v4.

Expand Down
2 changes: 1 addition & 1 deletion docs/latest/advanced/define.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: |

Define helpers can be used to shorten the amount of types you have to type
yourself in code. They are entirely optional as some developers prefer the
explicitness of types, other's like the convenience of `define.*` helpers.
explicitness of types, others like the convenience of `define.*` helpers.

Without define helpers:

Expand Down
2 changes: 1 addition & 1 deletion docs/latest/advanced/environment-variables.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: |
Error pages can be used to customize the page that is shown when an error occurs in the application.
How to use environment variables in Fresh, including public variables that are inlined into island bundles.
---

Environment variables in Deno are typically read via `Deno.env.get()` or
Expand Down
23 changes: 20 additions & 3 deletions docs/latest/advanced/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,13 @@ middleware. Contrary to generic error pages this handler cannot be nested.
## Throwing HTTP errors

If you need to bail out of execution and need to respond with a particular HTTP
error code, you can use Fresh's `HttpError` class.
error code, you can use Fresh's `HttpError` class:

```ts
import { HttpError } from "fresh";
```

`HttpError` takes a status code and an optional message:

```ts middleware/auth.ts
import { HttpError } from "fresh";
Expand All @@ -84,14 +90,22 @@ async function authMiddleware(ctx) {
throw new HttpError(404);
}

// Forbidden with a custom message
if (!isAdmin(user)) {
throw new HttpError(403, "Admin access required");
}

return await ctx.next();
}
```

You can check the status code of the thrown `HttpError` in your error handler:
When an `HttpError` is thrown, Fresh catches it and invokes the error handler.
You can check the status code in your error handler:

```ts main.ts
app.onError((ctx) => {
import { HttpError } from "fresh";

app.onError("*", (ctx) => {
if (ctx.error instanceof HttpError) {
const status = ctx.error.status;
return new Response("oops", { status });
Expand All @@ -100,3 +114,6 @@ app.onError((ctx) => {
// ...
});
```

`HttpError` is also available in the browser via `fresh/runtime` for use in
island code.
5 changes: 5 additions & 0 deletions docs/latest/advanced/head.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,10 @@ the matching element:
5. No matching element was found, Fresh will create a new one and append it to
`<head>`

When multiple `<Head>` components render an element with the same key, the
**last one rendered wins**. Since Fresh renders top-down (app wrapper → layout →
route → page component), a route page can override defaults set in `_app.tsx` by
using the same `key` prop.

> [info]: The `<title>`-tag is automatically deduplicated, even without a `key`
> prop.
21 changes: 21 additions & 0 deletions docs/latest/advanced/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,24 @@ description: |
---

This section of the documentation describes advanced functionality of Fresh.

- [App wrapper](/docs/advanced/app-wrapper) - Customize the outer HTML structure
- [Layouts](/docs/advanced/layouts) - Define programmatic layouts
- [Error handling](/docs/advanced/error-handling) - Custom error and 404 pages
- [Partials](/docs/advanced/partials) - Client-side partial page updates
- [Forms](/docs/advanced/forms) - Handle form submissions
- [Define helpers](/docs/advanced/define) - Type-safe route and middleware
helpers
- [Serialization](/docs/advanced/serialization) - What types can be passed as
island props
- [Environment variables](/docs/advanced/environment-variables) - Use env vars
in islands
- [Modifying &lt;head&gt;](/docs/advanced/head) - Manage meta tags, titles, and
styles
- [Vite plugin options](/docs/advanced/vite) - Configure the Fresh Vite plugin
- [OpenTelemetry](/docs/advanced/opentelemetry) - Built-in tracing and
observability
- [API Reference](/docs/advanced/api-reference) - All public exports from Fresh
- [Troubleshooting](/docs/advanced/troubleshooting) - Common issues and
solutions
- [Builder (Legacy)](/docs/advanced/builder) - Pre-Vite build system
33 changes: 30 additions & 3 deletions docs/latest/advanced/layouts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
description: "Create re-usable layouts across routes"
---

This page covers **programmatic layouts** defined via `app.layout()`. If you're
using file-based routing, see [Layouts (file-based)](/docs/concepts/layouts)
instead.

Layouts are plain Preact components that are inherited based on the matching
pattern. When you have a section on your site where all pages share the same
HTML structure and only the content changes, a layout is a neat way to abstract
Expand Down Expand Up @@ -32,14 +36,37 @@ If you browse to the `/` route, Fresh will render the following HTML
</div>
```

## Options
## Multiple layouts

You can register multiple layouts for different paths. Layouts are inherited
from parent paths — a layout at `"*"` applies to all routes, and more specific
layouts are added on top:

```ts main.ts
const app = new App()
.layout("*", MainLayout) // Applied to all routes
.layout("/admin/*", AdminLayout) // Added on top for /admin/* routes
.get("/", (ctx) => ctx.render(<h1>Home</h1>))
.get("/admin/dashboard", (ctx) => ctx.render(<h1>Dashboard</h1>));
```

For `/admin/dashboard`, both `MainLayout` and `AdminLayout` will wrap the page
component (MainLayout as the outer wrapper, AdminLayout as the inner).

## Overriding layouts

Add a layout and ignore all previously inherited ones.
Use `skipInheritedLayouts` to replace all inherited layouts with a single one:

```ts main.ts
app.layout("/foo/bar", MyComponent, { skipInheritedLayouts: true });
const app = new App()
.layout("*", MainLayout)
.layout("/landing", LandingLayout, { skipInheritedLayouts: true })
.get("/", (ctx) => ctx.render(<h1>Home</h1>)) // Uses MainLayout
.get("/landing", (ctx) => ctx.render(<h1>Landing</h1>)); // Uses only LandingLayout
```

## Options

Ignore the app wrapper component:

```ts main.ts
Expand Down
45 changes: 45 additions & 0 deletions docs/latest/advanced/opentelemetry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
description: |
Fresh has built-in OpenTelemetry instrumentation for tracing requests through middleware, handlers, and rendering.
---

Fresh automatically instruments key operations with
[OpenTelemetry](https://opentelemetry.io/) spans, giving you visibility into how
requests flow through your application.

## What's instrumented

Fresh creates spans for:

- **Middleware execution** — each middleware in the chain
- **Route handler execution** — handler function calls
- **Rendering** — server-side page rendering
- **Static file serving** — file lookups and responses
- **Lazy route loading** — dynamic imports of route modules

## Enabling tracing

Fresh uses the `@opentelemetry/api` package (the vendor-neutral API). Spans are
created automatically — you just need to provide an OpenTelemetry SDK and
exporter to collect them.

If no exporter is configured, the spans are silently discarded (no performance
overhead).

### With Deno's built-in OpenTelemetry

Deno has
[built-in OpenTelemetry support](https://docs.deno.com/runtime/fundamentals/open_telemetry/).
Enable it with the `OTEL_DENO` environment variable:

```sh Terminal
OTEL_DENO=true deno task start
```

This exports traces to an OTLP-compatible collector (configure the endpoint with
`OTEL_EXPORTER_OTLP_ENDPOINT`).

### With Deno Deploy

[Deno Deploy](https://deno.com/deploy) collects Fresh traces automatically when
using the Fresh preset — no configuration needed.
Loading
Loading