This reference documents every option available in the outpost-manifest.yaml file. For a quick introduction, see Getting Started.
File Location
The manifest file must be named outpost-manifest.yaml and placed in your theme’s root directory, alongside package.json.
your-theme/
├── package.json
├── outpost-manifest.yaml ← here
├── default.hbs
├── post.hbs
└── ...
Schema Overview
manifest_version: 1 # Required — must be 1
events:
default_tags: [] # Optional — tags for all event types
types: # Required — at least one type
type_key: # Your type identifier (e.g., "webinar")
label: "Display Name"
post_template: "custom-template" # Required
tags: []
supported_fields: []
required_fields: []
field_constraints: {}
custom_fields: []
messaging_states: []
Top-Level Fields
manifest_version
Required. Must be 1. This enables future schema evolution without breaking existing manifests.
events
Required. Contains all event-related configuration.
Events Section
Optional. Array of Ghost tag names applied to ALL event types when published.
events:
default_tags:
- "event"
- "registration-open"
Tags are strings. Invalid entries (non-strings) are silently ignored.
events.types
Required. Object where each key is an event type identifier and the value is that type’s configuration.
events:
types:
webinar:
# ... webinar config
workshop:
# ... workshop config
meetup:
# ... meetup config
Type keys should be lowercase with underscores (e.g., in_person, virtual_workshop). These keys are stored on event records and used for identification.
Event Type Configuration
Each event type supports the following fields:
post_template
Required. The Ghost custom template filename (without .hbs extension) used for this event type’s posts.
types:
webinar:
post_template: "custom-webinar"
This template must exist in your theme. Events using this type will have their Ghost posts set to use this template.
label
Optional. Human-readable name shown in the Outpost UI. Defaults to the type key with underscores replaced by spaces and title-cased.
types:
in_person:
label: "In-Person Event" # Shows as "In-Person Event" in dropdown
Optional. Array of Ghost tags specific to this event type. Merged with default_tags when publishing.
types:
webinar:
tags:
- "webinar"
- "online-event"
supported_fields
Optional. Array of standard field keys to show for this event type. If omitted, all standard fields are shown.
types:
webinar:
supported_fields:
- name
- description
- event_date
- event_time_start
- event_time_end
- event_time_zone
- platform_url
- access
See Standard Field Keys for all available fields.
required_fields
Optional. Array of field keys that must be filled before publishing. Must be a subset of supported_fields (or standard fields if supported_fields is omitted).
types:
webinar:
required_fields:
- name
- event_date
- platform_url
If a required field is not in supported_fields, it will be ignored with a warning.
field_constraints
Optional. Object defining validation constraints for specific fields.
types:
in_person:
field_constraints:
feature_image:
aspect_ratio: "16:9"
min_width: 1200
description:
max_length: 500
See Field Constraints for available constraint options.
custom_fields
Optional. Array of custom field definitions for theme-specific data.
types:
webinar:
custom_fields:
- key: speaker_name
label: "Speaker Name"
type: text
required: true
See Custom Field Types for complete options.
messaging_states
Optional. Array of messaging states to show in the event settings. If omitted, all seven states are shown.
types:
webinar:
messaging_states:
- can_register
- registered
- event_passed
See Messaging States for all available states.
Standard Field Keys
These are the built-in fields available for supported_fields and required_fields:
| Key | Description | Data Type |
|---|
name | Event name/title | string |
slug | URL-safe identifier | string |
description | Event description (used as post excerpt) | string |
event_date | Date of the event | date |
event_time_start | Start time | string (e.g., “10:00 am”) |
event_time_end | End time | string (e.g., “11:00 am”) |
event_time_zone | IANA timezone | string (e.g., “America/New_York”) |
location | Venue or location text | string |
platform_url | Virtual event platform link | URL string |
max_attendees | Capacity limit | integer |
feature_image | Featured/hero image | URL string |
access | Who can register | enum: anyone, free, paid |
rsvp_labels | Labels applied to registrants | array of strings |
registration_deadline | Registration cutoff date | date |
deadline_time_end | Registration cutoff time | string |
Field Constraints
Available constraints vary by field type:
Text/Textarea Fields
field_constraints:
description:
max_length: 500 # Maximum character count
pattern: "^[A-Z]" # Regex pattern (optional)
Image Fields
field_constraints:
feature_image:
aspect_ratio: "16:9" # Width:height ratio
min_width: 1200 # Minimum width in pixels
Number Fields
field_constraints:
max_attendees:
min: 1
max: 1000
Custom Field Types
Custom fields support these types:
text
Single-line text input.
- key: speaker_name
label: "Speaker Name"
type: text
required: true
help_text: "Full name of the presenter"
max_length: 100
pattern: "^[A-Za-z\\s]+$"
textarea
Multi-line text input.
- key: speaker_bio
label: "Speaker Bio"
type: textarea
required: false
max_length: 500
number
Numeric input with optional range constraints.
- key: session_duration
label: "Duration (minutes)"
type: number
required: true
min: 15
max: 480
select
Dropdown with predefined options.
- key: session_type
label: "Session Type"
type: select
required: true
options:
- Keynote
- Breakout
- Workshop
- Panel
Select fields must include an options array. Fields without options are skipped with an error.
url
URL input with validation.
- key: slides_url
label: "Slides URL"
type: url
required: false
help_text: "Link to presentation slides"
date
Date picker input.
- key: early_bird_deadline
label: "Early Bird Deadline"
type: date
required: false
toggle
Boolean switch input.
- key: is_recorded
label: "Will Be Recorded"
type: toggle
required: false
image
Image upload with optional constraints.
- key: speaker_photo
label: "Speaker Photo"
type: image
required: false
aspect_ratio: "1:1"
min_width: 400
max_file_size_kb: 2048
Custom Field Properties
All custom field types support these properties:
| Property | Type | Required | Description |
|---|
key | string | Yes | Unique identifier (no spaces, lowercase recommended) |
label | string | No | Display label (defaults to formatted key) |
type | string | Yes | One of the field types above |
required | boolean | No | Whether field must be filled (default: false) |
help_text | string | No | Helper text shown below the field |
Custom field keys must not collide with standard field keys. Keys like name, event_date, access, etc. will be rejected with an error.
Messaging States
Control which messaging states appear in the event settings editor:
| State | When Shown to Members |
|---|
can_register | Eligible member who hasn’t registered |
login_required_free | Guest on a free event |
login_required_paid | Guest on a paid event |
upgrade_required | Free member on a paid event |
registered | Member who has RSVP’d |
registration_closed | After registration deadline |
event_passed | After the event ends |
types:
webinar:
messaging_states:
- can_register
- registered
- event_passed
If omitted, all seven states are configurable.
Homepage Curation Section
Optional. Declares curated homepage regions that a publisher can fill from the Outpost UI. When a theme’s manifest includes a top-level homepage_curation key, Outpost shows a Homepage Curation screen (under Posts) where editors pick which post occupies each slot — without hand-editing tags in Ghost.
homepage_curation and events are independent top-level keys in the same outpost-manifest.yaml; a theme can declare either, both, or neither.
homepage_curation:
sections: # Required — one or more sections
- key: featured-us # Section identifier (unique)
name: "Featured (US)" # Display name in the curation UI
description: "Top-of-homepage hero carousel." # Optional helper text
picker: # Optional — controls the post picker
default_view: recent # Default tab when picking a post
recent_limit: 30 # How many recent posts to offer
recent_filter: # Optional — pre-scope picker to a tag
tag: local-news
slots: # Required — one or more slots
- { key: slot-1, label: "Slot 1", tag: hash-home-hero-slot-1 }
- { key: slot-2, label: "Slot 2", tag: hash-home-hero-slot-2 }
How slots work
Each slot binds one Ghost tag to one post. The theme renders whichever single post currently carries that tag; the curation UI simply swaps which post wears it. Slot tags are ordinary Ghost internal tags — a hash- prefix maps to a # internal tag.
| Field | Required | Description |
|---|
sections[].key | Yes | Unique identifier for the section |
sections[].name | Yes | Display name shown in the curation UI |
sections[].description | No | Helper text shown under the section |
sections[].picker.default_view | No | Default picker tab (e.g. recent) |
sections[].picker.recent_limit | No | Number of recent posts to list |
sections[].picker.recent_filter.tag | No | Restrict the picker to posts carrying this tag |
slots[].key | Yes | Unique identifier for the slot within its section |
slots[].label | Yes | Label shown above the slot in the UI |
slots[].tag | Yes | Ghost tag that binds a post to this slot |
Homepage Curation is an early Labs feature and currently ships in the single-file manifest format. A complete worked example is bundled with the docs as cascade-homepage-curation.yaml.
Error Handling
Outpost validates manifests during theme upload and stores errors in the manifest data. Invalid parts are stripped while valid parts are kept.
Error Categories
| Category | Severity | Behavior |
|---|
| YAML syntax error | Error | Manifest ignored entirely |
| Unknown manifest_version | Warning | Manifest ignored |
| Missing post_template | Error | Event type skipped |
| Unknown standard field | Warning | Field key ignored |
| Required field not in supported | Warning | Requirement ignored |
| Custom field key collision | Error | Custom field skipped |
| Unknown custom field type | Error | Custom field skipped |
| Missing options on select | Error | Custom field skipped |
Viewing Errors
Errors are visible in:
- Theme settings table (warning count with info button)
- Event editor (banner at top of form)
- Theme upload/refresh API response
Example Error Response
{
"_errors": [
{
"field": "types.webinar.post_template",
"message": "Missing required 'post_template'",
"severity": "error"
},
{
"field": "types.in_person.supported_fields",
"message": "Unknown standard field 'title'",
"severity": "warning"
}
]
}
Complete Example
manifest_version: 1
events:
default_tags:
- "event"
types:
webinar:
label: "Webinar"
post_template: "custom-webinar"
tags:
- "webinar"
- "online"
supported_fields:
- name
- description
- event_date
- event_time_start
- event_time_end
- event_time_zone
- platform_url
- feature_image
- access
- registration_deadline
- deadline_time_end
required_fields:
- name
- event_date
- platform_url
field_constraints:
feature_image:
aspect_ratio: "16:9"
min_width: 1200
description:
max_length: 300
custom_fields:
- key: speaker_name
label: "Speaker Name"
type: text
required: true
help_text: "Full name of the presenter"
- key: speaker_bio
label: "Speaker Bio"
type: textarea
required: false
max_length: 500
- key: session_type
label: "Session Type"
type: select
required: true
options:
- Live Presentation
- Q&A Session
- Workshop
- key: is_recorded
label: "Will Be Recorded"
type: toggle
messaging_states:
- can_register
- login_required_free
- registered
- event_passed
in_person:
label: "In-Person Event"
post_template: "custom-in-person"
tags:
- "in-person"
- "conference"
supported_fields:
- name
- description
- event_date
- event_time_start
- event_time_end
- event_time_zone
- location
- max_attendees
- feature_image
- access
required_fields:
- name
- event_date
- location
- feature_image
custom_fields:
- key: venue_address
label: "Venue Address"
type: textarea
required: true
- key: track
label: "Track"
type: select
required: true
options:
- Main Stage
- Workshop Room A
- Workshop Room B
- Networking Hall