Installation
Install Dyrected into an existing Next.js, Nuxt, React, or Vue app with a single CLI command.
Dyrected installs into an app you already have. The npx dyrected init command detects your framework, asks whether you want a Dyrected Cloud or self-hosted backend when that choice exists, installs the right packages, writes a starter config when needed, and mounts the admin for you. When it finishes, you run your dev server and log in at /admin.
Requirements
Before you install, make sure you have:
- Node.js 22 or newer (download).
- A package manager — pnpm is recommended, but npm, yarn, and bun all work. The CLI detects which one your project uses.
- A supported app to install into: Next.js (App Router), Nuxt 3, React, or Vue.
Next.js projects must use the App Router. Dyrected mounts its API as a
route handler, so init stops with an error if it finds a Pages Router
project without an app/ directory. Add an app/ directory first.
Dyrected Cloud is the fastest way to go live and works with every framework — it hosts the database, storage, and API for you, with no infrastructure to provision. See Setting up your Cloud site.
Next.js and Nuxt can also self-host the full backend inside your app when you want full control — that is the path this page walks through. React and Vue are a frontend and admin only, so they always connect to a Dyrected Cloud backend.
Quick install
From the root of your project, run:
npx dyrected initThe CLI walks you through setup in a few prompts:
- Confirms the framework it detected (or asks, if it can't tell).
- For Next.js and Nuxt, asks whether the backend should run in Dyrected Cloud or be self-hosted in your app.
- Asks which path the admin should use — the default is
admin, so editors log in at/admin. - On the self-hosted path, offers Quick Setup (SQLite + local file storage), which is the fastest way to get running locally. Decline it to choose a different database and storage adapter.
When it finishes, you have installed packages, environment variable templates, and rules files for AI coding agents. Next.js and Nuxt also get a starter dyrected.config.ts; self-hosted installs add the local API runtime, while Cloud installs add schema-sync support instead.
Choosing a database and storage adapter
Quick Setup uses SQLite and local file storage, which need no external services. Turn it down to pick from the supported adapters instead:
| Type | Options |
|---|---|
| Database | SQLite, PostgreSQL, MySQL, MongoDB |
| Storage | Local filesystem, AWS S3, Backblaze B2, Cloudinary |
The CLI installs the matching @dyrected/db-* and @dyrected/storage-* package and writes both into your config. You can change adapters later by editing dyrected.config.ts. See Database and Storage adapters for the full list and configuration.
Non-interactive install
To skip the prompts — useful in scripts or for AI agents — pass the answers as flags:
For a Cloud-backed install:
npx dyrected init -y -f next -b cloud -p adminFor a self-hosted install:
npx dyrected init -y -f next -b self-hosted -d postgres -s s3 -p admin-y/--yesaccepts defaults without prompting-f/--frameworksets the framework (next,nuxt,react,vue)-b/--backendsets the backend mode (cloud,self-hosted)-d/--dbsets the database adapter (sqlite,postgres,mysql,mongodb) for self-hosted installs-s/--storagesets the storage adapter (local,s3,b2,cloudinary) for self-hosted installs-p/--pathsets the admin path (yourwebsite.com/any-thing-you like)
What the CLI creates
Every project gets the same three shared files: .env and .env.example (environment variable templates for your database, storage, and secrets) and .dyrected/ai-rules.md, which teaches AI coding agents how to work with Dyrected. init also drops pointer files for common agents (AGENTS.md, CLAUDE.md, Copilot, and Cursor) — commit these so agents follow the right patterns.
The rest depends on your framework. init detects a src/ directory and adjusts the paths automatically.
Next.js can either connect to Dyrected Cloud or run the full backend inside your app. The Next.js App Router is required either way.
dyrected.config.ts— your content model. On self-hosted installs it also includes database and storage settings.app/admin/page.tsx— the admin panel, served at the path you chose.instrumentation.ts— logs the admin URL and the active Dyrected API URL on server start.
On the self-hosted path, init also writes app/dyrected/[...route]/route.ts and mounts the content API under /dyrected.
Cloud installs use DYRECTED_URL, DYRECTED_API_KEY, DYRECTED_SITE_ID, and their NEXT_PUBLIC_* equivalents. Self-hosted installs use DATABASE_URL, DYRECTED_JWT_SECRET, and ENCRYPTION_KEY for the local runtime.
Nuxt can also connect to Dyrected Cloud or run the full backend inside your app, so init writes a config and the admin page, then registers the module.
dyrected.config.ts— your content model. On self-hosted installs it also includes database and storage settings.pages/admin/index.vue— the admin panel (written underapp/pages/if you use anapp/directory).nuxt.config.ts—initadds@dyrected/nuxtto yourmodules. On self-hosted installs it mounts the content API; on Cloud installs it points the admin at your Cloud site.
Cloud installs use DYRECTED_URL, DYRECTED_API_KEY, DYRECTED_SITE_ID, and their NUXT_PUBLIC_* equivalents. Self-hosted installs use DATABASE_URL, DYRECTED_JWT_SECRET, and ENCRYPTION_KEY for the local runtime.
React installs @dyrected/react only — it connects to a Dyrected Cloud backend, so there is no local dyrected.config.ts.
admin.tsx— an admin component (written undersrc/when present).initdoes not register this route for you. You must add a router entry for/adminyourself and point it at this component before the admin is reachable.
Connection settings come from Vite env vars: VITE_DYRECTED_URL, VITE_DYRECTED_API_KEY, and VITE_DYRECTED_SITE_ID.
Vue installs @dyrected/vue only — it connects to a Dyrected Cloud backend, so there is no local dyrected.config.ts.
views/AdminView.vue— an admin component (written undersrc/when present).initdoes not register this route for you. You must add a router entry for/adminyourself and point it at this view before the admin is reachable.
Connection settings come from Vite env vars: VITE_DYRECTED_URL, VITE_DYRECTED_API_KEY, and VITE_DYRECTED_SITE_ID.
The generated config
For Next.js and Nuxt projects, dyrected.config.ts is the source of truth for your CMS. (React and Vue apps connect to a Dyrected Cloud backend that owns this config.) With Quick Setup, the starter config wires SQLite and local storage and defines example collections and globals so you have something to see on first load:
import {
defineCollection,
defineGlobal,
defineConfig,
defineTextField,
defineMultiSelectField,
defineRichTextField,
defineRelationshipField,
defineArrayField,
defineTextareaField,
} from "@dyrected/core";
import { sqliteAdapter } from "@dyrected/db-sqlite";
import { localStorage } from "@dyrected/storage-local";
// ── Admin Auth ────────────────────────────────────────────────────────────
// Reserved collection — sole login gateway for the Dyrected dashboard.
// Email + password are auto-managed; declare only extra fields here.
const Admins = defineCollection({
slug: "__admins",
labels: { singular: "Admin", plural: "Admins" },
auth: true,
admin: { icon: "Users", useAsTitle: "name" },
fields: [
defineTextField({ name: "name", required: true }),
defineMultiSelectField({
name: "roles",
options: ["admin", "editor"],
defaultValue: ["admin"],
}),
],
});
// ── Collections ──────────────────────────────────────────────────────────
const Media = defineCollection({
slug: "media",
labels: { singular: "Media", plural: "Media" },
upload: true,
admin: { icon: "Image", useAsTitle: "alt" },
fields: [defineTextField({ name: "alt" })],
});
const Pages = defineCollection({
slug: "pages",
labels: { singular: "Page", plural: "Pages" },
admin: {
icon: "FileText",
useAsTitle: "title",
// Jexl expression evaluated against the document (+ siteUrl). Relative
// results are prefixed with your site URL automatically.
previewUrl: "slug == 'home' ? '/' : '/' + slug",
},
fields: [
defineTextField({ name: "title", required: true }),
defineTextField({ name: "slug", required: true }),
defineRichTextField({ name: "content" }),
defineRelationshipField({ name: "featuredImage", relationTo: "media" }),
],
});
const Posts = defineCollection({
slug: "posts",
labels: { singular: "Post", plural: "Posts" },
admin: { icon: "Newspaper", useAsTitle: "title" },
fields: [
defineTextField({ name: "title", required: true }),
defineRichTextField({ name: "content" }),
defineRelationshipField({ name: "featuredImage", relationTo: "media" }),
],
});
// ── Globals ───────────────────────────────────────────────────────────────
const Navigation = defineGlobal({
slug: "navigation",
label: "Navigation",
admin: { icon: "Menu" },
fields: [
defineArrayField({
name: "menuItems",
fields: [
defineTextField({ name: "label" }),
defineRelationshipField({ name: "link", relationTo: "pages" }),
],
}),
],
});
const Settings = defineGlobal({
slug: "settings",
label: "Site Settings",
admin: { icon: "Settings" },
fields: [
defineTextField({ name: "siteName" }),
defineRelationshipField({ name: "logo", relationTo: "media" }),
defineTextareaField({ name: "footerText" }),
],
});
// ── Config ────────────────────────────────────────────────────────────────
export default defineConfig({
collections: [Admins, Media, Pages, Posts],
globals: [Navigation, Settings],
db: sqliteAdapter({ filename: "./data.db" }),
storage: localStorage({
uploadDir: "./public/uploads",
staticUrlPrefix: "/uploads",
}),
});The reserved __admins collection is the login gateway for the dashboard — email and password are managed for you, so you only declare extra fields. Each collection sets an admin.icon (a Lucide name shown in the sidebar) and admin.useAsTitle (the field used as the document's display title). Pages also sets admin.previewUrl — a Jexl expression evaluated against the document (plus siteUrl) to build the URL the admin previews; relative results are prefixed with your site URL. Replace these examples with your own content model. See Core concepts for how collections and globals fit together, and Configuration for the full config reference.
Launch the app
- Copy
.env.exampleto.envand fill in the values. At minimum, setDYRECTED_JWT_SECRETandENCRYPTION_KEYto your own secrets. Also setDATABASE_URLwhen you're not using SQLite, plus any storage credentials for S3, B2, or Cloudinary. - Start your dev server, for example
pnpm dev. - Open the admin URL printed in your console — by default
http://localhost:3000/admin— and create your first admin account.
Once the admin loads and you can log in, generate typed helpers for your content model:
npm run dyrected:generate-typesdyrected init adds that script to package.json for you. If you prefer to run the CLI directly, npx dyrected generate:types still works too.
That command writes dyrected-types.ts into your app's source directory (src/, or app/ in Nuxt) so TypeScript picks it up. It includes the generated DyrectedSchema type — and registers it globally, so the SDK client and framework hooks are typed against your schema automatically, no generics needed.
Next steps
Core Concepts
Understand collections, globals, and fields before you model your own content.
Configuration
See the full dyrected.config.ts reference and how it drives the rest of the system.
Next.js quick start
Model a schema, display content, and invite editors in a real Next.js app.
Admin
See how the admin panel works and where editors manage content.
Generating types
Get end-to-end type safety from your content model to your frontend.
Dyrected with AI agents
Use the generated ai-rules.md and the Dyrected skill to build with coding agents.