npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

payload-plugin-scheduler

v1.1.0

Published

Scheduled posts plugin for PayloadCMS

Readme

payload-plugin-scheduler

Plugin that adds an imperative field-based scheduling flow on top of Payload's native functionality, with at-a-glance schedule status in the admin UI.

Starting in v3, Payload has a built-in workflow for scheduling posts via the job queue and "Schedule Publish" drawer. This plugin adds a configurable Date field to opted-in collections and globals that, when set to a future date, automatically queues a schedulePublish job in the background with waitUntil set to that date. This results in a more ergonomic workflow for editors where they can view the schedule status at a glance in the document editor, and sort/filter by publish time in the list view.

This plugin was originally written for Payload v2, and included a background scheduler that's since been superseded by v3's native queue. For Payload v2, use version <=0.1.3.

ci status

UI Demo

Publish date field

List view

Requirements

  • Payload v3

Installation

npm add payload-plugin-scheduler

Usage

After configuring the plugin, ensure that you've regenerated payload's import map, otherwise the custom components won't display.

// payload.config.ts

import { buildConfig } from 'payload'
import { ScheduledPostPlugin } from 'payload-plugin-scheduler'

import Pages from './collections/Pages'
import Posts from './collections/Posts'
import Home from './globals/Home'

export default buildConfig({
  collections: [Pages, Posts, Users],
  globals: [Home],
  plugins: [
    ScheduledPostPlugin({
      collections: ['pages', 'posts'],
      globals: ['home'],
      interval: 10,
    }),
  ],
})

Running Jobs

This plugin creates Payload Jobs; it does not run the job worker for you. Your host app is responsible for running Payload's Jobs Queue.

See Payload's docs for current deployment guidance:

Options

Enabled collections and globals must support drafts. The plugin merges the required scheduled-publish draft config into versions.drafts.schedulePublish and preserves existing version/draft settings.

collections?: string[]

ScheduledPostPlugin({
  collections: ['pages', 'posts'],
})

globals?: string[]

ScheduledPostPlugin({
  globals: ['home'],
})

interval?: number

Time interval, in minutes, passed to the Date field's time picker and Payload's scheduled-publish draft config. Defaults to 5.

ScheduledPostPlugin({
  collections: ['posts'],
  interval: 15,
})

Your job queue cron interval should match this value, eg autoRun: [{ cron: '*/5 * * * *' }].

executionAccess?: 'user' | 'override'

Controls whose access permissions Payload uses when the scheduled publish job executes. Defaults to user.

  • user stores the authenticated scheduling user's ID on the job. Payload re-checks that user's current permissions at execution time. Scheduling without an authenticated user throws an error.
  • override omits the user from the job, causing Payload to execute it with access overridden.
ScheduledPostPlugin({
  collections: ['posts'],
  executionAccess: 'override',
})

publishDate?: object

Configure the generated publish-date field.

ScheduledPostPlugin({
  collections: ['posts'],
  // these are the default values
  publishDate: {
    name: 'publish_date',
    label: 'Publish Date',
    index: true,
    admin: {
      position: 'sidebar',
    },
  },
})

All properties are configurable except type, timezone, admin.date.pickerAppearance, admin.date.timeIntervals, admin.components.afterInput, and admin.components.Cell.

Manual Field Placement

By default, the plugin injects the publish-date field into every opted-in collection and global. If you need to place the field manually, use the exported publishDate() helper.

import type { CollectionConfig } from 'payload'
import { publishDate } from 'payload-plugin-scheduler'

export const Posts: CollectionConfig = {
  slug: 'posts',
  versions: {
    drafts: true,
  },
  fields: [
    {
      type: 'tabs',
      tabs: [
        {
          label: 'Content',
          fields: [
            {
              name: 'title',
              type: 'text',
            },
          ],
        },
        {
          label: 'Publishing',
          fields: [publishDate()],
        },
      ],
    },
  ],
}

Manual placement is only valid inside collections or globals that are opted in through ScheduledPostPlugin({ collections, globals }).

You can also pass arguments to publishDate to override the global publishDate options, eg to override the admin display properties on a one-off basis. Overrides are merged with the top-level publishDate config, with name being the only field that's only configurable at the global level.

publishDate({
  admin: {
    width: '50%',
    description: 'Custom description for this collection only'
  }
})

SafeRelationship

A drop-in replacement for Payload's relationship field, this is a helper field that throws an error if a user attempts to publish a document with relationships to unpublished documents.

import type { Field } from 'payload'
import { SafeRelationship } from 'payload-plugin-scheduler'

export const featuredContent: Field = SafeRelationship({
  name: 'featured_content',
  relationTo: ['posts', 'pages'],
  hasMany: true,
})

Debugging

Set DEBUG=payload-plugin-scheduler in your runtime env to enable debug logging.

Contributing

After cloning the repo and installing dependencies, run pnpm exec simple-git-hooks to setup automatic pre-commit linting.

Migration From v2

The v3 plugin no longer creates or writes to a plugin-owned scheduled_posts collection, and it no longer uses node-schedule. Scheduled publishes are represented as native Payload schedulePublish jobs in Payload's jobs collection.

To upgrade:

  • Remove any application code that reads from or customizes scheduled_posts.
  • Configure and run Payload Jobs in the host app. Dedicated servers and serverless deployments need different worker/cron strategies.
  • If you use Payload admin.timezones, verify the resulting <fieldName>_tz values in your own scheduling flow.
  • Generate and run a new database migration.
  • Rebuild payload's import map.