Tutorials
Use Strife as your Astro CMS
Use Strife as the CMS for your Astro site: start from the Strife starter or add Strife to your own project, define your content with defineType, deploy it with the CLI, render pages from the content index, and turn on live preview.
Strife gives your Astro site a CMS. Editors write and publish in Strife Studio, and your Astro pages read the content on each request and render it with your own components. @strifeapp/astro connects your site to your team's database, and live preview shows editors their changes on your site as they type.
There are two ways to start:
- Start from the Strife starter, an Astro site that is set up and has a first page.
- Add Strife to your own Astro project.
You need Node.js 22.12 or later and Astro 5, 6 or 7. If you are new to Strife, How Strife works explains the parts.
Start from the Strife starter
Run this where you want the new project:
npm create @strifeThe CLI signs you in through your browser, and lets you pick a team or create a new one. It then sets up the starter, writes the connection secret to .env, deploys the starter's schema and adds a first page. Start the site:
npm run devOpen the address Astro prints, usually http://localhost:4321. The page shows its heading and body from Strife. Open the page in Studio, where the CLI printed a link, and edit it to watch your site change as you type.
The starter is a working example of everything below:
- the schema is in
schemas/home.ts - the query is in
src/pages/index.astro - live preview is in
src/components/HomeContent.svelte
Add Strife to your own Astro project
1. Install the packages
npx astro add @strifeapp/astro
npm install @strifeapp/strife
npm install --save-dev @strifeapp/cliastro addinstalls the integration and adds it toastro.config.mjs.@strifeapp/strifehas live preview and the schema tools.@strifeapp/cligives you thestrifecommand.
2. Connect the project to your team
From your project's folder, run:
npx strife .The CLI signs you in, links the folder to a team (or creates one), and writes STRIFE_SECRET to .env. It also adds .env to .gitignore. The secret contains your certificate's private key, so keep it out of version control and out of the browser. See How your site connects.
3. Configure Astro
// astro.config.mjs
import { defineConfig } from 'astro/config';
import strife from '@strifeapp/astro';
export default defineConfig({
// Live preview needs pages rendered on request.
output: 'server',
// The address Studio previews a new team's site on.
server: { port: 4321 },
integrations: [strife()],
});astro add adds the integration but not output: 'server', so add it yourself. Live preview reads a preview token on each request, and that only happens for pages rendered on request.
A team the CLI creates previews http://localhost:4321, so keep the dev server on that port. An existing team previews the site address in its settings.
Then declare the types that @strifeapp/astro doesn't ship yet, in src/env.d.ts:
/// <reference types="astro/client" />
declare module 'strife:store' {
import type { DocumentStore } from 'ravendb';
export const store: DocumentStore;
}
declare namespace App {
interface Locals {
editMode?: boolean;
}
}4. Define your content
Write a schema for each kind of page. Create schemas/article.ts:
import { defineType, fields } from '@strifeapp/strife/schema';
export const article = defineType({
name: 'article',
title: 'Article',
type: 'document',
fields: {
heading: fields.text({ label: 'Heading', localizable: true }),
body: fields.html({ label: 'Body', localizable: true }),
},
});Point the CLI at your schemas in strife.config.ts:
import { defineConfig, glob } from '@strifeapp/strife/schema';
export default defineConfig({
schema: glob('./schemas/**/*.ts'),
});Deploy them, and generate types for them:
npx strife push
npx strife typegen generatestrife pushcreates the Article template in your team and deploysContent/ByUrl, the content index your pages query. Run it again whenever you change a schema.strife typegen generatewrites an interface for each template to.strife/types.ts, such asArticle extends Content.
Schemas and the Field Reference list everything you can define.
5. Write a page in Studio
Open Studio, create an Article, give it an address and publish it. See Your first page in the user guide.
6. Render pages
Create src/pages/[...slug].astro. It finds the page for the address being visited and renders it:
---
import { store } from 'strife:store';
import LivePreview from '@strifeapp/astro/LivePreview.astro';
import type { Article } from '../../.strife/types';
const session = store.openSession();
const find = (status: string) =>
session
.query<Article>({ indexName: 'Content/ByUrl' })
.whereEquals('url', Astro.url.pathname)
.whereEquals('locale', 'en')
.whereEquals('status', status)
.selectFields(['displayName', 'heading', 'body'])
.noCaching()
.firstOrNull();
// Visitors see the published version. In Strife's live preview, show the
// pending edits first, then a page that was never published.
const page = Astro.locals.editMode
? ((await find('draft')) ?? (await find('unpublished')) ?? (await find('published')))
: await find('published');
if (!page) {
return new Response(null, { status: 404 });
}
---
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{page.displayName}</title>
<LivePreview />
</head>
<body>
<h1>{page.heading}</h1>
<article set:html={page.body} />
</body>
</html>Content/ByUrlhas a row for each page and language. A page's pending edits and scheduled publish are rows too, at the same address, so the query always filters onstatus.- Visitors get the
publishedrow. - In live preview,
Astro.locals.editModeistrue. The page then shows the pending edits (draft), or a page that was never published (unpublished). - Index URL describes every kind of row.
- Visitors get the
selectFieldsreturns each field in the row's language. Without it, the query returns the whole document, where a translated field is an object such as{ en: '…' }..noCaching()stops the RavenDB client from caching a response for every address someone tries, which matters in a catch-all route.set:htmlrenders the rich text body's HTML.
Start the dev server with npm run dev and open the page's address.
7. Turn on live preview
<LivePreview /> loads Strife's live preview script when your page is open in Studio, and does nothing for visitors. Place it once, in the <head> of your layout.
To update the page while editors type, read the live document in a client component with subscribe from @strifeapp/strife. It calls your function with the document on every change. A translated field can arrive as text or as an object keyed by language. Here is a Svelte component. It needs Astro's Svelte integration (npx astro add svelte), listed before strife() in integrations as in the starter:
<!-- src/components/ArticleContent.svelte -->
<script lang="ts">
import { onMount, untrack } from 'svelte';
import { subscribe } from '@strifeapp/strife';
type Localized = string | Record<string, unknown> | null | undefined;
let { heading: initialHeading, body: initialBody, locale = 'en' } = $props();
function text(value: Localized): string {
if (value == null) return '';
if (typeof value === 'string') return value;
const v = value[locale] ?? Object.values(value)[0];
return typeof v === 'string' ? v : '';
}
let heading = $state(untrack(() => text(initialHeading)));
let body = $state(untrack(() => text(initialBody)));
onMount(() =>
subscribe((data) => {
const doc = data as Record<string, Localized>;
if ('heading' in doc) heading = text(doc.heading);
if ('body' in doc) body = text(doc.body);
}),
);
</script>
<h1>{heading}</h1>
<article>{@html body}</article>Render it from your page with <ArticleContent client:load heading={page.heading} body={page.body} />. The same pattern works in React or Vue: call subscribe when the component mounts, and return its result to stop listening. See Live preview for the details.
Deploy
astro dev works without more setup. For production builds, add the Astro adapter for your host:
| Deploy target | Adapter | Install |
|---|---|---|
Self-hosted Node.js | @astrojs/node | npx astro add node |
Vercel | @astrojs/vercel | npx astro add vercel |
Netlify | @astrojs/netlify | npx astro add netlify |
Cloudflare Workers | @astrojs/cloudflare | npx astro add cloudflare |
Then set STRIFE_SECRET as a server-side secret in your host's environment settings. @strifeapp/astro reads it on the server when a page is requested, and never builds it into your site's files. The certificate makes the value long, and some hosts limit how long a variable can be: the @strifeapp/astro README lists the limits.
More for your site
- Snapshots: let editors share a link to a frozen copy of a page for review. See Snapshots.
- Open in Strife: a toolbar that takes editors from a page on your site to the same page in Studio. See Open in Strife.
- Insights:
<Insights />from@strifeapp/astroreports how fast your pages are for real visitors, and checks accessibility in the live preview. See the@strifeapp/astroREADME.