Introduction to the Update API for Drupal 8
This documentation needs review. See "Help improve this page" in the sidebar.
What you need to update
You need to provide code that performs an update to stored data whenever your module makes a change to its data model. A data model change is any change that makes stored data on an existing site incompatible with that site's updated codebase. In Drupal 8, there are several ways your data model can change, described in the following sections.
Content entity and field changes
Configurable fields can be created programmatically this way:
/**
* Add field foo to Bar vocabulary.
*/
function mymodule_update_9002() {
$module_path = drupal_get_path('module', 'mymodule');
$yml = Yaml::parse(file_get_contents($module_path . '/config/install/field.storage.taxonomy_term.field_foo.yml'));
if (!FieldStorageConfig::loadByName($yml['entity_type'], $yml['field_name'])) {
FieldStorageConfig::create($yml)->save();
}
$yml = Yaml::parse(file_get_contents($module_path . '/config/install/field.field.taxonomy_term.bar.field_foo.yml'));
if (!FieldConfig::loadByName($yml['entity_type'], $yml['bundle'], $yml['field_name'])) {
FieldConfig::create($yml)->save();
}
}
/**
* Setup Foo bar View display.
*/
function mymodule_update_9003() {
$field_name = 'field_foo';
$properties = [
'targetEntityType' => 'taxonomy_term',
'bundle' => 'bar',
];
if ($view_displays = \Drupal::entityTypeManager()->getStorage('entity_view_display')->loadByProperties($properties)) {
foreach ($view_displays as $view_display) {
$view_display_config = [
'label' => 'above',
'region' => 'hidden',
];
$view_display->setComponent($field_name, $view_display_config);
$view_display->save();
}
}
}
/**
* Setup Foo bar Form display.
*/
function mymodule_update_9004() {
$field_name = 'field_foo';
$properties = [
'targetEntityType' => 'taxonomy_term',
'bundle' => 'bar',
];
if ($form_displays = \Drupal::entityTypeManager()->getStorage('entity_form_display')->loadByProperties($properties)) {
foreach ($form_displays as $form_display) {
$form_display_config = [
'type' => 'boolean_checkbox',
'settings' => [
'display_label' => TRUE,
],
'weight' => 1,
];
$form_display->setComponent($field_name, $form_display_config);
$form_display->save();
}
}
}
TODO: Needs rewrite since automatic updates were removed.
Configuration schema changes
Changes to your configuration schema include:
- Removing or renaming a configuration key.
- Adding a configuration key. Even if the additions are backwards-compatible in terms of stored data, they will introduce unexpected differences in exporting configuration the next time the configuration is saved.
- Changing the expected data type, allowable values, or array structure of a configuration key.
- Changing the expected default value of a configuration key.
- Changes to configuration dependencies (e.g. changes to a plugin's dependencies or an implementation of
ConfigEntityInterface::calculateDependencies()). - Etc.
For example, changing the way a particular Views plugin defines its configuration would require an update to all saved views configuration items that use that plugin.
Database schema changes
If your module defines its own hook_schema() for database tables, the following types of changes are possible:
- Adding, changing, or removing a database table or field.
- Moving stored data to different fields or tables.
- Changing the format of stored data (for example, changing the stored format of user-entered paths, requiring a different password hashing algorithm, or storing a UUID as an external key instead of a serial ID).
Writing update code
Once you have identified that your module is making a data model change, you will need to use hook_update_N() to provide code that updates data so that it fits with your new data model. How to do this depends on the type of data model change (see previous section for list) and the specifics are covered in other pages (except the common piece in the skeleton of hook_update_N() section below):
- Content entities and fields
- This is covered on the child page about entity and field updates.
- Configuration
- This is covered on the child page about configuration updates.
- Configuration Entity
- This is covered here about configuration entity updates.
- Database schema
- This is covered on the child page about database updates.
Skeleton of hook_update_N()
All update code will need to go into a hook_update_N() function. Assuming your module's short/machine name is mymodule, this goes into your mymodule.install file, and looks something like this:
/**
* Write a line or two here about what the updates are for.
* This is shown to users on the update.php page.
*/
function mymodule_update_8001(&$sandbox) {
}
For each change in a module that requires one or more actions to be performed when updating a site, add a new implementation of hook_update_N() to your my_module.install file (assuming my_module is the machine name of your module). Implementations of hook_update_N() are named (module name)_update_(number).
The number (N) must be higher than hook_update_last_removed().
The numbers are normally composed of three parts:
- 1 or 2 digits for Drupal core compatibility (Drupal 8, 9, 10, etc.). This convention must be followed. If your module is compatible with multiple major versions (e.g., it has a
core_version_requirementof '^8.8 || ^9'), use the lowest major core branch it is compatible with (8 in this example). - 1 or 2 digits for your module's major release version. Examples:
- For 8.x-1.* or 1.y.x (semantic versioning), use 1 or 01.
- For 8.x-2.* or 2.y.x, use 2 or 02.
- For 8.x-10.* or 10.y.x, use 10.
- For core 8.0.x, use 0 or 00.
- For core 8.1.x, use 1 or 01.
- For core 8.10.x, use 10.
This convention is optional but suggested for clarity. Note: While four-digit update hooks are standard, if you follow the above convention, you may run into the need to start using five digits if you get to a major (or, for core, a minor) version 10. This will work fine; what matters is that you must ALWAYS increase the number when a new update hook is added. For example, if you add hook_update_81001(), you cannot later add hook_update_9101(). Instead, you would need to use hook_update_90101().
- 2 digits for sequential counting, starting with 01. Note that the x000 number can never be used: the lowest update number that will be recognized and run is 8001.
@todo Remove reference to CORE_MINIMUM_SCHEMA_VERSION (e.g., x001) once https://www.drupal.org/project/drupal/issues/3106712 is resolved.
Testing updates
Updates should be tested. Ideally, they would be tested manually, and there would also be an automated test.
Testing updates manually
To test your update code manually, or to see whether you need to write your own update code for a data model change:
- Start with a site that is running your old code, and add some data related to this code (content, configuration, etc.).
- Apply the code change or patch to the site.
- Visit the update.php page and run any available updates.
- Manually try using the data in the relevant parts of the UI (view the content, view pages that are generated from the configuration, etc.). See if it all works without error messages.
Writing automated tests for updates
This is covered in the child page about automated tests.
Example code:
/**
* Create new database table by update hook{custom_table}.
*/
function my_module_update_8206() {
$database = \Drupal::database();
$schema = $database->schema();
$table_name = 'custom_table';
$table_schema = [
'description' => 'Use for capturing payment data',
'fields' => [
'id' => [
'description' => 'Id.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
],
'club_id' => [
'description' => 'Club id',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
],
'month' => [
'description' => 'Month',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
],
'year' => [
'description' => 'Year',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
],
'payment_status' => [
'description' => '0 = not paid; 1 = paid ( Payment Status)',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
],
'reason' => [
'description' => 'Delay Reason',
'type' => 'text',
'null' => TRUE,
],
],
'primary key' => ['id'],
];
$schema->createTable($table_name, $table_schema);
}
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion
Still on Drupal 7? Security support for Drupal 7 ended on 5 January 2025. Please visit our Drupal 7 End of Life resources page to review all of your options.