Docs

Quick start

Install Orbiter and run the admin in under 5 minutes.

Requirements

  • Node.js 20+
  • npm 10+
  • An existing Astro 6 project, or start fresh with orbiter init

Option A — Scaffold a new project

npm install -g @a83/orbiter-cli
orbiter init my-site
cd my-site
npm install

This creates a complete Astro + Orbiter project with sample collections, pages, and a pre-configured content.pod.

Option B — Add to an existing Astro site

1. Install the packages

npm install @a83/orbiter-integration @a83/orbiter-admin @astrojs/node
Note: @astrojs/node@^10 targets Astro 6. Use @astrojs/node@^9 for Astro 5.

2. Configure Astro

// astro.config.mjs
import { defineConfig } from 'astro/config';
import orbiter from '@a83/orbiter-integration';
import node from '@astrojs/node';

export default defineConfig({
  output: 'server',
  adapter: node({ mode: 'standalone' }),
  integrations: [
    orbiter({ pod: './content.pod' }),
  ],
});

3. Create the pod and first user

npx @a83/orbiter-cli init --pod-only ./content.pod

Or manually:

node --input-type=module << 'EOF'
import { createPod, hashPassword } from '@a83/orbiter-core';
import { randomUUID } from 'node:crypto';
const db = createPod('./content.pod', { site: { name: 'My Site' } });
const hash = await hashPassword('change-me');
db.insertUser(randomUUID(), 'admin', hash, 'admin');
db.close();
console.log('Pod created.');
EOF

Start the admin

ORBITER_POD=$(pwd)/content.pod npx @a83/orbiter-admin

Open http://localhost:4322 and log in with your credentials.

Always use an absolute path for ORBITER_POD. The server changes its working directory internally, so relative paths break.

Start the Astro dev server

In a second terminal:

npm run dev

Both processes share the same content.pod. Changes saved in the admin appear in the Astro site after a browser reload (Astro re-reads the pod on each dev-server request).

Read content in a page

---
// src/pages/blog/[slug].astro
import { getCollection, getEntry } from 'orbiter:collections';

export async function getStaticPaths() {
  const posts = await getCollection('posts');
  return posts.map(post => ({ params: { slug: post.slug } }));
}

const post = await getEntry('posts', Astro.params.slug);
---

<article>
  <h1>{post.data.title}</h1>
  <div set:html={post.data.body} />
</article>

Demo (monorepo)

If you cloned the Orbiter repo:

git clone https://github.com/aeon022/orbiter.git
cd orbiter
npm install
npm run seed
ORBITER_POD=$(pwd)/apps/demo/demo.pod npm run dev --workspace=packages/admin

Admin at http://localhost:4322 — login: admin / admin