contentful-orm
v1.0.4
Published
A TypeScript-first ORM for Contentful CMS that enables a code-first approach to content modeling
Downloads
649
Maintainers
Readme
Contentful ORM
A TypeScript-first ORM for Contentful CMS that enables a code-first approach to content modeling. Define your content types using TypeScript decorators and automatically sync them with Contentful.
Features
- 🎯 Code-First Development
- 📝 TypeScript Stage 3 Decorators
- 🔄 Automatic Content Type Synchronization
- 🛠️ CLI Tools
- 💪 Type Safety
- 🌐 Localization Support
- 🔗 Reference Field Support
- ✨ Rich Text Support
Supported Field Types
The following field types are supported:
Symbol
- For short text content (Contentful's Symbol type)Text
- For long text content (Contentful's Text type)RichText
- For rich text content with formattingNumber
- For decimal numbersInteger
- For whole numbersDate
- For date and time valuesLocation
- For geographical coordinatesMedia
- For media assets (images, videos, etc.)Boolean
- For true/false valuesReference
- For references to other content typesArray
- For arrays of any other supported typeObject
- For JSON objects
Each field type can be configured with additional options:
@Field({
type: ContentfulFieldType.Text, // The field type
required: true, // Whether the field is required
localized: false, // Whether the field supports localization
validations: [], // Array of validation rules
disabled: false, // Whether the field is read-only
omitted: false, // Whether the field is hidden
// Array-specific options
itemsType: ContentfulFieldType.Text, // Type of array items (for Array type)
itemsValidations: [], // Validations for array items
itemsLinkType: 'Entry' // Link type for Reference/Media arrays
})
Specialized Field Decorators
For better type safety and developer experience, specialized decorators are available for different field types:
Basic Fields
@SymbolField({
required: true,
validations: [
Validations.size(1, 50)
]
})
declare name: string;
@IntegerField({
required: true,
validations: [
Validations.range(0, 100)
]
})
declare quantity: number;
@ObjectField()
declare metadata: Record<string, any>;
Media Fields
@MediaField({
required: true,
validations: [
Validations.linkMimetypeGroup(['image'])
]
})
declare featuredImage: any;
Reference Fields
@ReferenceField({
linkType: 'Entry',
required: true,
validations: [
Validations.linkContentType(['category'])
]
})
declare category: any;
Array Fields
@ArrayField({
itemsType: ContentfulFieldType.Media,
itemsLinkType: 'Asset',
itemsValidations: [
Validations.linkMimetypeGroup(['image'])
]
})
declare gallery?: any[];
Validation Builders
The library provides type-safe validation builders to help prevent runtime errors:
import { Validations } from 'contentful-orm';
// Text validations
Validations.size(10, 100) // Min/max length
Validations.regexp('^[A-Z]', 'i') // Regular expression with flags
Validations.unique() // Unique value
// Number validations
Validations.range(0, 100) // Min/max value
// Link validations
Validations.linkContentType(['category', 'author']) // Valid content types
Validations.linkMimetypeGroup(['image', 'video']) // Valid mime types
// Rich text validations
Validations.enabledMarks(['bold', 'italic']) // Allowed formatting
Validations.enabledNodeTypes(['paragraph', 'heading-1']) // Allowed blocks
Complete Example
Here's a complete example of a Product content type using all available field types:
@ContentType({
name: 'product',
displayField: 'name',
description: 'A product with all available field types'
})
export class Product {
@SymbolField({
required: true,
validations: [
Validations.size(1, 50)
]
})
declare name: string;
@Field({
type: ContentfulFieldType.Text,
required: true
})
declare description: string;
@Field({
type: ContentfulFieldType.RichText,
validations: [
Validations.enabledMarks(['bold', 'italic']),
Validations.enabledNodeTypes(['paragraph', 'heading-1'])
]
})
declare details: any;
@IntegerField({
required: true,
validations: [
Validations.range(0)
]
})
declare quantity: number;
@Field({
type: ContentfulFieldType.Number,
validations: [
Validations.range(0.01)
]
})
declare price: number;
@Field({
type: ContentfulFieldType.Date,
required: true
})
declare releaseDate: Date;
@Field({
type: ContentfulFieldType.Location
})
declare storeLocation: any;
@MediaField({
required: true,
validations: [
Validations.linkMimetypeGroup(['image'])
]
})
declare image: any;
@Field({
type: ContentfulFieldType.Boolean,
required: true
})
declare isAvailable: boolean;
@ReferenceField({
linkType: 'Entry',
validations: [
Validations.linkContentType(['category'])
]
})
declare category: any;
@ArrayField({
itemsType: ContentfulFieldType.Reference,
itemsLinkType: 'Entry',
itemsValidations: [
Validations.linkContentType(['tag'])
]
})
declare tags: any[];
@ObjectField()
declare metadata: Record<string, any>;
@Field({
type: ContentfulFieldType.Text,
disabled: true
})
declare sku: string;
@Field({
type: ContentfulFieldType.Text,
omitted: true
})
declare internalNotes: string;
}
## Examples
The repository includes several examples to help you get started:
### Blog Example
A complete example of a blog implementation using Contentful ORM. Located in `/examples/blog`, this example demonstrates:
- Full project structure
- Entity definitions
- Environment configuration
- TypeScript configuration
### Case Study Example
A single-file example (`/examples/case-study.ts`) showing how to define a case study content type with:
- Rich text content
- Media fields
- Reference fields
- Field validations
### Direct TypeScript Example
Located in `/examples/direct-ts`, this example demonstrates direct TypeScript usage of the ORM.
For more details, check out the examples in the repository's `/examples` directory.
## Requirements
- TypeScript 5.2 or higher
- Node.js 18 or higher
## Setup Guide
### Installation
```bash
# Using npm
npm install contentful-orm reflect-metadata cross-env ts-node --save-dev
# Using pnpm
pnpm add contentful-orm reflect-metadata cross-env ts-node -D
# Using yarn
yarn add contentful-orm reflect-metadata cross-env ts-node --dev
Configuration
1. Environment Variables
Create a .env
file in your project root:
CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_ACCESS_TOKEN=your_management_access_token
CONTENTFUL_ENVIRONMENT_ID=master # or your preferred environment
Important: The
CONTENTFUL_ACCESS_TOKEN
should be a Management Access Token, not a Content Delivery/Preview token. You can generate one from Contentful's web app under Settings > API Keys > Content management tokens.
2. TypeScript Configuration
Your tsconfig.json
must include the following settings for decorators and metadata to work properly:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"module": "ESNext",
"moduleResolution": "node",
"target": "ESNext"
}
}
3. Package Configuration
Update your package.json
to include the following scripts:
{
"scripts": {
"clean": "rimraf dist",
"build": "npm run clean && tsc",
"sync": "npm run build && contentful-orm sync --path=\"dist/entities/**/*.js\""
}
}
Install the required dev dependencies:
pnpm add -D rimraf
Entity Setup
- Create your entity files with
.ts
extension in your entities directory - Export all entities from an
index.ts
file
Example entity structure:
// src/entities/author.ts
import { ContentType, Field, ContentfulFieldType } from 'contentful-orm';
@ContentType({
name: 'author',
displayField: 'name',
description: 'Author of blog posts'
})
export class Author {
@Field({
type: ContentfulFieldType.Text,
required: true,
validations: [{
size: { min: 2, max: 100 }
}]
})
name!: string;
}
Running the Sync
After setting up your entities and configuration:
- Build your TypeScript files:
pnpm build
- Run the sync command:
pnpm sync
The sync process will:
- Build your TypeScript files
- Find all entity files in the specified path
- Create or update content types in Contentful
- Handle versioning and publishing automatically
Troubleshooting
If you encounter sync issues:
- Ensure your Management Access Token has the correct permissions
- Check that all import paths use
.js
extensions - Verify that your TypeScript configuration includes decorator and metadata settings
- Make sure all array field validations use
itemsValidations
instead ofitems
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
https://github.com/Moga-Digital-LLC/contentful-orm
License
MIT