Data models are used to define and manage data structures in your application. They enable you to map your data to the underlying database and create relationships between different entities. When a model is defined and installed by a Swell App, it becomes an integral part of a store’s database.

A data model configuration has the ability to enhance a merchant store’s own database schema in a secure, observable, and isolated manner.

Since Swell data models are dynamically instantiated as REST endpoints, any models you define will essentially modify a merchant’s own API in what feels like a first-class, native interface. See architecture if you’re interested in how it works.

You can create a new data model by adding a configuration in the app's models/ folder, or by using the following CLI command:

swell create model

→ See the CLI reference for more details and options.

Here's an example of a new data model:

models/things.json
{
  "collection": "things",
  "label": "Things",
  "fields": {
    "name": {
      "type": "string",
      "required": true
    },
    "description": {
      "type": "string"
    }
  }
}

Once a model is defined, Swell dynamically generates backend API endpoints, eliminating the need to manually create custom endpoints for data services, and streamlining the process of exposing your data to the frontend or other services.

A data model schema supports various field types, such as scalar values, arrays, nested objects, and links to other models, allowing you to create diverse data structures. Links help establish relationships between models, making it easier to navigate and work with related data. Scalar field types include basic data types such as strings, integers, and booleans. Arrays allow for collections of values, while nested objects enable you to create complex, hierarchical data structures.

See the Data model reference for more information.

Models include built-in validation and type coercion mechanisms. The key principle is to ensure that your data is consistent without being overly rigid and hard to work with. Validation constraints include required fields, unique constraints, and custom validation rules. Automatic type coercion ensures that API input data is converted to the appropriate data type when querying and creating records.

Events can be configured to emit when a specific action occurs, such as creating, updating, or deleting a record with specific properties. Webhooks and Functions can be subscribed to these events. Triggers are model-defined actions that respond to record conditions and can be used to propagate changes to other records automatically. By using events and triggers, you can create a dynamic and responsive application that automatically reacts to changes in your data.

When working with models, you often need to fetch and consistently display data. Default query parameters allow you to define standard settings for data retrieval, such as pagination, sorting order, and the number of items to display per page.

A primary field is the main identifier for a record, used for lookup and reference purposes. The primary field should be unique and is set to id by default. A secondary field allows for a more human-readable alternative identifier, for example, a product slug.

Swell employs techniques to optimize database queries automatically, while App-specific indexes can be created on one or more fields and can include additional options, such as expiration time. By using indexes, you can significantly improve the performance of your application, especially when dealing with large amounts of data.

Model namespaces are a way to group and organize related models. They help prevent naming conflicts between different models in an app and provide a clear structure for organizing your data. Note that all App-defined models and fields are scoped to API keys and dynamically layered to prevent naming collisions across applications. Therefore, it’s not necessary to use namespaces for any purpose other than convenience and organization.

You can extend existing models to create new models with additional properties and behaviors through model inheritance. This enables you to create a hierarchy of models sharing common properties and behaviors, promoting organization and maintainability in your application. To extend a model, specify the parent model using the extends property in the model definition. Additionally, indicate the version of the parent model to inherit from with the extends_version property.

Swell offers two specialized types of models: singular and abstract. A singular model represents a single record in your application, such as a site configuration or a global setting. An abstract model serves as a base for other models to extend, but cannot be instantiated directly. Abstract models are useful for creating reusable data structures and enforcing consistent behavior across your schema.

Swell automatically tracks changes to models over time using semantic versioning. When a model is updated, the version number is incremented as a patch, although you can also specify a new major or minor version in your configuration. This helps maintain compatibility between different versions of your application without breaking existing functionality.

There are two types of model configurations representing both low-level database fields and high-level content management interfaces. To learn more about these concepts, read the Models introduction and our general guide on Data model customization.

With an understanding of how models work, you can construct app configurations that automatically introduce new models as well as new fields to standard models when installed.

A model configuration can either instantiate a new collection, such as above, or append to an existing collection such as products.

Here’s an example of appending fields to an existing collection:

models/products.json
{
  "collection": "products",
  "fields": {
    "app_property_1": {
      "type": "string",
      "required": true
    },
    "app_property_2": {
      "type": "int"
    }
  }
}

In the above example, the resulting model will append the field definition my_app_field to the existing products model.

Notice how there is no explicit namespace on the field object. This is intentional, as Swell handles namespace conflicts in a unique way that supports overlapping fields among apps, without causing conflicts internally or externally. It works because each API key is identified by a specific app, and data is isolated by an internal structure. App models and fields can still be accessed without an app-scoped API key, however, the model API endpoint necessarily has a namespace prefix in that case. See our app introduction for more details.

All model collections are private by default, but to support accessing data from the frontend API you can declare individual fields or entire models as public, along with specific query parameters that can limit the range of fields returned using a public key.

Here’s an example model with a public field:

{
  "collection": "vendors",
  "label": "Vendors",
  "fields": {
    "name": {
      "type": "string",
      "required": true,
      "public": true
    },
    "active": {
      "type": "bool"
    },
    "description": {
      "type": "string"
    }
  },
  "public_permissions": {
    "query": {
      "active": true
    },
    "expands": {
      "products": {
        "url": "/products",
        "params": {
          "vendor_id": "id"
        },
        "data": {
          "active": true
        }
      }
    }
  }
}

With at least 1 public field declared, all records can be accessed by the frontend API, with only the public fields being returned in a response. In addition, you can limit the range of results to only include active records using public_permissions, and specify how expand parameters should be treated for the collection in a public scope.