Dyrected
Start Here

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 init

The CLI walks you through setup in a few prompts:

  1. Confirms the framework it detected (or asks, if it can't tell).
  2. For Next.js and Nuxt, asks whether the backend should run in Dyrected Cloud or be self-hosted in your app.
  3. Asks which path the admin should use — the default is admin, so editors log in at /admin.
  4. 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:

TypeOptions
DatabaseSQLite, PostgreSQL, MySQL, MongoDB
StorageLocal 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 admin

For a self-hosted install:

npx dyrected init -y -f next -b self-hosted -d postgres -s s3 -p admin
  • -y / --yes accepts defaults without prompting
  • -f / --framework sets the framework (next, nuxt, react, vue)
  • -b / --backend sets the backend mode (cloud, self-hosted)
  • -d / --db sets the database adapter (sqlite, postgres, mysql, mongodb) for self-hosted installs
  • -s / --storage sets the storage adapter (local, s3, b2, cloudinary) for self-hosted installs
  • -p / --path sets 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
instrumentation.ts
  • 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
nuxt.config.ts
  • 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 under app/pages/ if you use an app/ directory).
  • nuxt.config.tsinit adds @dyrected/nuxt to your modules. 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
  • admin.tsx — an admin component (written under src/ when present). init does not register this route for you. You must add a router entry for /admin yourself 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.

AdminView.vue
  • views/AdminView.vue — an admin component (written under src/ when present). init does not register this route for you. You must add a router entry for /admin yourself 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

  1. Copy .env.example to .env and fill in the values. At minimum, set DYRECTED_JWT_SECRET and ENCRYPTION_KEY to your own secrets. Also set DATABASE_URL when you're not using SQLite, plus any storage credentials for S3, B2, or Cloudinary.
  2. Start your dev server, for example pnpm dev.
  3. 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-types

dyrected 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

On this page

Dyrected| Cloud

Get your backend ready in minutes

Use a managed database, storage, APIs, and admin dashboard without setting up the infrastructure yourself.

Set Up My Backend