- docs
- FlowFuse User Manuals
- Using FlowFuse
- Getting Started
- Static asset service
- Bill of Materials
- FlowFuse Concepts
- Changing the Stack
- Custom Hostnames
- Device Groups
- DevOps Pipelines
- Environment Variables
- FlowFuse Assistant
- FlowFuse File Nodes
- FlowFuse Persistent Context
- FlowFuse Project Nodes
- High Availability mode
- HTTP Access Tokens
- Instance Settings
- Logging
- Shared Team Library
- Snapshots
- Team Broker
- Teams
- User Settings
- FlowFuse API
- Migrating a Node-RED project to FlowFuse
- Device Agent
- Device Agent
- FlowFuse Device Agent Introduction
- Quick Start
- Installation
- Quick Start with Web UI
- Register your Device
- Running the Agent
- Deploying your Flows
- Hardware Guides
- FlowFuse Cloud
- FlowFuse Cloud
- FlowFuse Self-Hosted
- Quick Start
- Installing FlowFuse
- Overview
- Configuring FlowFuse
- DNS Setup
- Docker install
- Docker from AWS Market Place
- Docker on Digital Ocean
- Add Project Stacks on Docker
- Docker Engine on Windows
- Email configuration
- First Run Setup
- FlowFuse File Storage
- Install FlowFuse on Kubernetes
- Upgrading FlowFuse
- Administering FlowFuse
- Administering FlowFuse
- Configuring Single Sign-On (SSO)
- Licensing
- Monitoring
- Telemetry
- User Management
- Support
- Community Support
- Premium Support
- Debugging Node-RED issues
- Contributing
- Contributing to FlowFuse
- Introduction
- Adding Template Settings
- API Design
- Creating debug stack containers
- Database migrations
- FlowFuse Architecture
- Local Install
- State Flows
- Device Editor
- Invite External Users
- User Login Flows
- Reset Password Flow
- Project Creation
- Instance states
- User Sign up Flow
- Team creation Flow
- Team Broker
- Working with Feature Flags
# Database Migrations
Any changes made to the database models must include migrations that can modify the database state from one state to another.
Whilst we use Sequelize as our ORM layer, we do not use the migration tooling it provides - we have our own.
# Creating migrations
# Filename
A migration is provided as JavaScript in the directory forge/db/migrations
. Its file name must follow the pattern:
YYYYMMDD-nn-description.js
YYYYMMDD
- the date the migration is addednn
- a two digit numberdescription
- a name for the migration
For example 20220204-01-add-billing.js
.
This ensures the migrations have a natural order to be applied. The nn
part of the name allows multiple migrations to be added on the same day but is kept in the right order.
# Structure
The migration code should use the following layout:
module.exports = {
up: async (context) => {
// Apply the migration
},
down: async (context) => {
// Remove the migration
}
}
The up
function applies to the migration. This can be to create new tables, add columns to existing ones - whatever is needed.
The down
function reverses the migration. It should restore the database back to how it was prior to the migration.
The context
argument is an instance of Sequelize.QueryInterface that can be used to perform operations on the database.
# Applying migrations
Migrations are applied automatically at the start of the FlowFuse application. Down migrations are not yet supported.
# Considerations when writing migrations
Whilst migrations give us the ability to make changes to the database, they must be used with great care. A failing migration will prevent the platform from starting and may require manual intervention. Everything should be done to avoid that from happening.
Certain types of migration need particular guidance and care over.
# Adding constraints
If a migration is adding a new constraint to an existing table, you need to consider very carefully what impact that could have on an existing system with real data.
For example, adding a new 'unique' constraint where you cannot guarantee that constraint hasn't already been broken. What strategy will you use to guard against that or to help recover from it? What additional testing is needed for the migration to verify its behavior in those situations?
The preferred method to add a new unique constraint is by adding a new index to the database. This is because SQLite doesn't provide a way to alter columns that doesn't involve dropping the whole table and triggering any cascade triggers.