Designing Your Content Schema
A schema in FoxNose is the blueprint for your content. It defines what fields your resources have, what type of data each field accepts, and how that data should be validated. Well-designed schemas are essential for both data quality and effective search.
Core Concepts
Schemas Live in Folders
Every collection folder has its own schema that defines the structure of resources within it. When you create a folder, you define its schema by adding fields—think of it like designing a database table, but with built-in support for search, localization, and AI.
Schema Versioning
Schemas are versioned, allowing you to evolve your data model safely:
- Create a draft version — Start with a new schema version or copy from an existing one
- Add and configure fields — Define your content structure
- Publish the version — Make it active and start creating content
Once published, a schema version is locked. To make changes, create a new draft version, modify it, then publish. This ensures your existing content always matches a known schema.
Field Types
FoxNose provides a comprehensive set of field types to model any content structure.
Text Fields
| Type | Use Case | Max Length | Vectorizable |
|---|---|---|---|
string | Titles, names, short text | 255 chars | Yes |
text | Articles, descriptions, long content | Unlimited | Yes |
When to use each:
- Use
stringfor titles, labels, identifiers, and any short text - Use
textfor article bodies, descriptions, and content you want to search
Both types support vectorizable: true for semantic search.
Numeric Fields
| Type | Use Case | Example |
|---|---|---|
integer | Counts, IDs, whole numbers | 42, -10, 0 |
number | Prices, ratings, measurements | 19.99, 4.5, 0.001 |
Both support minimum, maximum, and enum validation.
Boolean
Simple true/false flags:
{
"key": "is_published",
"type": "boolean",
"required": true
}
Date and Time
| Type | Format | Example |
|---|---|---|
date | YYYY-MM-DD | 2024-03-15 |
time | HH:MM:SS[.SSS]Z | 14:30:00Z |
datetime | ISO 8601 (UTC) | 2024-03-15T14:30:00Z |
All date/time types support from and to range validation.
JSON
For arbitrary structured data when you need flexibility:
{
"key": "metadata",
"type": "json"
}
JSON fields cannot be multiple, searchable, or vectorizable. Use them for configuration objects or data you don't need to query.
Relationship Fields
Connect resources across folders:
| Type | Cardinality | Use Case |
|---|---|---|
reference | One-to-one | Link to a single resource (author, category) |
relation | One-to-many | Link to multiple resources (tags, related articles) |
// Single author reference
{
"key": "author",
"type": "reference",
"meta": { "target": "8xk2m4pq" }
}
// Multiple tags
{
"key": "tags",
"type": "relation",
"meta": { "target": "t9n3v7ws", "max_items": 10 }
}
The target value is the folder's unique key, which you can find in the dashboard or via the Management API.
Reference field features:
- Supports cross-collection joins in search queries
- Can be populated to include full referenced objects in responses
Constraints:
- Reference fields cannot be placed inside object arrays (objects with
multiple: true). This ensures data integrity for join operations.
Structural Fields
| Type | Use Case |
|---|---|
object | Group related fields together |
nested | Embed a component schema (components only) |
Objects let you create hierarchical field structures:
// Parent object
{
"key": "seo",
"type": "object"
}
// Child fields (with parent: "seo")
{
"key": "title",
"type": "string",
"parent": "seo"
}
{
"key": "description",
"type": "text",
"parent": "seo"
}
This creates a nested structure: seo.title, seo.description.
Field Configuration
Beyond type, fields have configuration options that control their behavior.
Making Fields Searchable
FoxNose supports two types of search, controlled by field flags:
| Flag | Search Type | Use Case |
|---|---|---|
searchable: true | Filtering and full-text search | Using filters and keyword matching with typo tolerance |
vectorizable: true | Semantic search | AI-powered meaning-based search |
You can enable both on the same field:
{
"key": "summary",
"type": "text",
"searchable": true, // Enables keyword search
"vectorizable": true // Enables semantic search
}
This lets you use hybrid search—combining exact keyword matches with semantic understanding.
Vector embeddings are generated automatically when you save content. They're stored separately and billed based on vector storage usage.
Custom embeddings: If you generate embeddings externally (e.g., via OpenAI or Cohere), use a vector type field instead. Store your embedding arrays directly in resources and query them via Vector Field Search.
Localization
Mark fields as localizable: true to store translations:
{
"key": "title",
"type": "string",
"localizable": true
}
Localized fields store values per language:
{
"title": {
"en": "Introduction to AI",
"fr": "Introduction à l'IA",
"de": "Einführung in KI"
}
}
See Managing Multilingual Content for the full localization workflow.
Validation
Control what values are accepted:
String validation:
{
"key": "email",
"type": "string",
"meta": {
"format": "email", // Built-in format
"max_length": 255
}
}
{
"key": "slug",
"type": "string",
"meta": {
"pattern": "^[a-z0-9-]+$", // Custom regex
"max_length": 100
}
}
{
"key": "status",
"type": "string",
"meta": {
"enum": ["draft", "review", "published"] // Allowed values
}
}
Available string formats: email, hostname, uuid, ipv4, ipv6, uri, uri-reference
Numeric validation:
{
"key": "rating",
"type": "number",
"meta": {
"minimum": 0,
"maximum": 5,
"multiple_of": 0.5 // Only 0, 0.5, 1, 1.5, etc.
}
}
Date range validation:
{
"key": "event_date",
"type": "date",
"meta": {
"from": "2024-01-01",
"to": "2025-12-31"
}
}
Arrays (Multiple Values)
Any field can accept arrays with multiple: true:
{
"key": "keywords",
"type": "string",
"multiple": true,
"meta": {
"min_items": 1,
"max_items": 10,
"unique_items": true
}
}
Private Fields
Hide fields from the Flux API with private: true:
{
"key": "internal_notes",
"type": "text",
"private": true
}
Private fields are only accessible through the Management API. Use them for editorial notes, internal IDs, or any data that shouldn't be public.
Required and Nullable
| Flag | Meaning |
|---|---|
required: true | Field must have a value when creating/updating |
nullable: true | Field explicitly accepts null as a value |
Common Schema Patterns
Blog Article
Fields:
├── title (string, required, searchable, localizable)
├── slug (string, required, format: pattern)
├── summary (text, vectorizable, localizable)
├── body (text, searchable, vectorizable, localizable)
├── author (reference → authors folder)
├── tags (relation → tags folder)
├── category (string, enum: ["tech", "business", "lifestyle"])
├── published_at (datetime)
├── seo (object)
│ ├── meta_title (string, localizable)
│ └── meta_description (text, localizable)
└── internal_notes (text, private)
Product Catalog
Fields:
├── name (string, required, searchable, localizable)
├── description (text, vectorizable, localizable)
├── sku (string, required, unique pattern)
├── price (number, minimum: 0)
├── category (reference → categories folder)
├── tags (relation → tags folder)
├── specs (object)
│ ├── weight (number)
│ ├── dimensions (string)
│ └── material (string)
├── images (string, multiple, format: uri)
└── in_stock (boolean)
FAQ / Knowledge Base
Optimized for RAG and AI agents:
Fields:
├── question (string, required, searchable, vectorizable)
├── answer (text, required, searchable, vectorizable)
├── category (string, enum: [...])
├── keywords (string, multiple, searchable)
└── last_verified (date)
Why this works for AI:
- Both
questionandanswerare vectorizable—queries can match either - Keywords provide additional search surface
- Category enables filtered search ("Find AI answers about billing")
Schema Evolution
Safe Changes
These changes won't break existing content:
- Adding optional fields (without
required: true) - Increasing
max_lengthormax_items - Removing enum values (if no content uses them)
- Adding new enum values
- Making a required field optional
Breaking Changes
These require data migration:
- Adding required fields (existing content won't have values)
- Decreasing
max_length(existing values might exceed) - Changing field types
- Removing fields (consider deprecating first)
Migration Strategy
- Create a new draft schema version
- Add new optional fields
- Publish the new version
- Backfill data for new required fields via Management API
- Update field to required in next version if needed
Next Steps
- Understanding Semantic Search — Learn how vectorizable fields power AI search
- Organizing Content with Folders — Structure your content hierarchy
- Search & Filtering Guide — Query your content effectively
- Fields API Reference — Complete API documentation