Migrating to Workflows
Learn how to upgrade your existing string-based status fields to the new Editorial Approval Workflow.
Move an existing status field over to Dyrected's built-in Workflows, and get draft/publish handling, per-role permissions, and a full change history without maintaining any of it yourself. This guide walks that migration step by step.
If you built your project before Workflows existed, you probably used a string field (like status or _status) plus access rules to hide unpublished content. Workflows replace that pattern: Dyrected now keeps a separate published copy of each document (the "snapshot" that anonymous visitors see), records every state change, and enforces which roles may publish or reject — all built in.
Remove the old status field
Remove your custom status field from the collection definition.
export const Posts = defineCollection({
slug: "posts",
- fields: [
- { name: "status", type: "select", options: ["draft", "published"], defaultValue: "draft" },
- { name: "title", type: "text" }
- ]
+ fields: [
+ { name: "title", type: "text" }
+ ]
})Enable the Workflow
Add the publishingWorkflow() (or your custom workflow definition) to the collection:
+import { publishingWorkflow } from "@dyrected/core"
export const Posts = defineCollection({
slug: "posts",
+ workflow: publishingWorkflow(),
fields: [
{ name: "title", type: "text" }
]
})Update Custom Filters
If your frontend or API clients previously queried for published content by checking the status field (e.g., ?where={"status":{"equals":"published"}}), you can remove this check entirely.
When workflows are enabled, the client.find() and client.findOne() endpoints automatically materialize the public snapshot for anonymous users. Drafts are safely hidden without needing manual filters.
Run the Data Migration
Workflow state is stored internally as __workflow. API responses expose the safe, request-specific metadata as _workflow. Published rows also need a __published snapshot, so migrate existing data before enabling the workflow configuration.
Write a script to read each document and apply the correct state:
import { db } from "@dyrected/core"
async function migrateStatuses() {
const posts = await db.find({ collection: "posts", limit: 1000 })
for (const post of posts.docs) {
const isPublished = post.status === "published"
// The public snapshot is every content field minus the old status and any internal keys.
const { id, status, __workflow, __published, ...publicFields } = post
await db.update({
collection: "posts",
id: post.id,
data: {
__workflow: {
state: isPublished ? "published" : "draft",
revision: 1,
...(isPublished ? {
publishedRevision: 1,
publishedAt: new Date().toISOString()
} : {})
},
...(isPublished ? { __published: publicFields } : {})
}
})
}
}Remember to run this data migration script before updating the collection configuration in production. Documents missing __workflow, or published documents missing __published, are not served through the workflow-aware public API.