Skip to content

Quickstart

Louise is a toolkit for building editable sites on Astro + Cloudflare Workers—content, commerce, media, forms, auth, and AI as composable primitives. Editing the live page in place is the headline; this page gets you from zero to it.

You don’t have to install anything to evaluate Louise:

This whole docs-and-marketing site is itself built with Louise, so the demos are the product.

The steps below wire inline editing into an existing Astro on Cloudflare Workers app (the @astrojs/cloudflare adapter, with a D1 binding on env.DB). Inline editing is progressive enhancement—you server-render normally, then mark the editable regions and mount the client in edit mode.

Terminal window
pnpm add louise-toolkit
# peers for what this quickstart uses: Drizzle (db) + the inline-edit client
pnpm add drizzle-orm solid-js prosekit @prosekit/pm

Louise’s heavier dependencies are optional peers—a route that only imports louise-toolkit/errors pulls in nothing extra. Install peers per export you use.

The marker is "<collection>:<key>:<field>"—the collection, the row key, and the field the client will PATCH.

---
// src/pages/index.astro — render the value from your own D1 row as usual.
const settings = /* your Drizzle query over env.DB */;
---
<h1 data-louise-field="settings:1:heroHeadline">{settings.heroHeadline}</h1>

It self-gates: if the page has no markers (that is, it wasn’t rendered in edit mode) mountLouise() does nothing—so published pages ship no editor JS.

import { mountLouise } from "louise-toolkit/client";
mountLouise();

The client sends one PATCH per changed field to your editor route. Louise’s saveRoute builds that route for you—you pass your own table, an allowlist of writable fields, and a resolveEditor that decides who may edit.

// src/pages/api/louise/[...path].ts — mounted at /api/louise/*
import { saveRoute, runEditorRoute } from "louise-toolkit/editor";
import { siteSettings } from "../../../schema"; // your Drizzle table
const route = saveRoute({
// Placeholder gate — returns an editor or null. Swap for real auth (step 5).
resolveEditor: (request) => (isEditor(request) ? { id: "you" } : null),
collections: {
settings: { table: siteSettings, fields: ["heroHeadline"] }, // allowlist!
},
});
export const ALL = (ctx) => runEditorRoute(route, ctx.request, ctx.locals.runtime.env);

Only allowlisted fields are writable—a forged request can never touch an unlisted column.

Step 4 used a placeholder resolveEditor. In production, resolve a real editor session—Louise ships a better-auth integration and a same-origin/CSRF guard. See Auth & edit mode for the session flow that turns a viewer into an in-place editor, and marks the page for edit mode so mountLouise() activates.