Last updated 28 May 2014. Created on 24 February 2006.
Edited by drupalshrek, josh.fabean, zet, add1sun. Log in to edit this page.

For Drupal 7 see Writing .install files (Drupal 7.x).
For Drupal 6 see Writing .install files (Drupal 6.x).

A .install file is run the first time a module is enabled, and is used to run setup procedures as required by the module. The most common task is creating database tables and fields. The .install file does not have any special syntax. It is merely a PHP file with a different extension.

.install files are also used to perform updates when a new version of a module needs it.

Install instructions

Install instructions are enclosed in a _install() function. This hook will be called when the module is first enabled. Any number of functions can reside here, but the most typical use is to create the necessary tables for your module.

If you are creating tables, please follow proper SQL naming conventions.

Here is an example of creating a module table:

// nodereference.install

function nodereference_install() {
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      // the {tablename} syntax is so multisite installs can add a
      // prefix to the table name as set in the settings.php file
      db_query("CREATE TABLE {node_field_nodereference_data} (
          vid int unsigned NOT NULL default '0',
          field_name varchar(32) NOT NULL default '',
          delta int unsigned NOT NULL default '0',
          field_nid int unsigned NOT NULL default '0',
          PRIMARY KEY  (vid,field_name,delta)
        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
    case 'pgsql':
      db_query("CREATE TABLE {node_field_nodereference_data} (
          vid serial CHECK (vid >= 0),
          field_name varchar(32) NOT NULL default '',
          delta integer NOT NULL default '0' CHECK (delta >= 0),
          field_nid integer NOT NULL default '0' CHECK (field_nid >= 0),
          PRIMARY KEY  (vid, field_name, delta)

      // Pgsql requires keys and indexes to be defined separately.
      // It's important to name the index as {tablename}_fieldname_idx
      // (the trailing _idx!) so update scripts can be written easily
      db_query("CREATE INDEX {node_field_nodereference_data}_field_name_idx
                ON {node_field_nodereference_data} (field_name)");

Update instructions

.install files can also include update instructions, which are used through update.php like regular Drupal updates. Each update is placed in a modulename_update_x() function (where x is an incrementing integer). Updates should always increment by 1.

If you need to include hook_update_N, a new numbering scheme has been proposed which several module maintainers have already adopted. The API for the hook is here.

All updates should return an array listing all the actions performed and whether they succeeded. Each action is an array containing a success boolean and a query string.

Note that if you add an update hook to your .install file you need to also update the install hook so that it contains the latest code. When a module is installed the first time, only the install hook will be fired and it will assume that is most current. Update hooks are only used when updating an existing installation.

Simple usage

The update_sql() function returns such a success/query pair, so it is the easiest way to perform updates. For example:

// example.install

function example_update_1() {
  $items = array();
  $items[] = update_sql("ALTER TABLE {example} ADD new_column text");
  $items[] = update_sql("ALTER TABLE {example} DROP old_column");
  return $items;

Also see database/ in 4.7 or modules/system/system.install in 5.x for lots of examples.

Multi-part updates

Some updates may take quite a while depending on the size of the site. To avoid time-outs, they can be performed in smaller pieces across multiple PHP requests.

To make a multi-part update, all you need to do is add a special #finished entry to the return array, set to 0. The update system will keep calling your update function until you return 1 for #finished (or provide no #finished flag at all).

However, you may return any number between 0 and 1 for #finished, which represents the progress in your particular update. This is used to provide more accurate feedback to the user while it is going on.

Note that, because your update may be spread over multiple requests, any state information that you need to keep needs to be stored in the user session. Global or static variables will not work.

For example:

// Make all node titles uppercase, 20 at a time.
function example_update_2() {
  // See if we are being called for the first time
  if (!isset($_SESSION['example_update_2_nid'])) {
    // These variables keep track of our progress
    $_SESSION['example_update_2_nid'] = 0;
    $_SESSION['example_update_2_max'] = db_result(db_query('SELECT MAX(nid) FROM {node}')); 

  // Fetch the next 20 nodes
  $result = db_query_range('SELECT nid, title FROM {node} WHERE nid > %d ORDER BY nid ASC', $_SESSION['example_update_2_nid'], 0, 20);
  while ($node = db_fetch_object($result)) {
    $node->title = drupal_strtoupper($node->title);
    db_query("UPDATE {node} SET title = '%s' WHERE nid = %d", $node->title, $node->nid);
    $_SESSION['example_update_2_nid'] = $node->nid; 

  // See if we are done
  if ($_SESSION['example_update_2_nid'] < $_SESSION['example_update_2_max']) {
    // Not done yet. Return the progress.
    return array('#finished' => $_SESSION['example_update_2_nid'] / $_SESSION['example_update_2_max']);
  else {
    // Done. Clean up and indicate we're finished.
    return array('#finished' => 1);

Some things to note in this example:

  • We decided not to return information about each individual query, because it would become unwieldy very quickly.
  • We chose 20 for the amount of nodes to process at a time. Any sufficiently small number will also work, as the update system will repeat your update in a single request if there is time.
  • We unset the session variables again when we're done.

Uninstall Instructions

Since Drupal 5.x, the hook_uninstall function is also available in a .install file and gets fired when a module is uninstalled. This function generally includes dropping tables and deleting variables specific to that module. For example, from the search module found in core:

function search_uninstall() {
  db_query('DROP TABLE {search_dataset}');
  db_query('DROP TABLE {search_index}');
  db_query('DROP TABLE {search_total}');

You can also include functions to clear the cache. If you would like to completely clear all cache tables, regardless of whether their contents are ready to expire, you should add the following to your hook_uninstall function:

  cache_clear_all('*', 'cache', TRUE);
  cache_clear_all('*', 'cache_filter', TRUE);
  cache_clear_all('*', 'cache_menu', TRUE);
  cache_clear_all('*', 'cache_page', TRUE);

Note that merely disabling the module will not run hook_uninstall(), so you will not lose all your module's data. In order to run hook_uninstall() for the module (and LOSE all your module's data), use the 'uninstall' tab in the modules page after disabling the module.

Note about already installed modules

If the module you are writing the .install file for is already installed then the install/update(s) will not trigger even if you disable/enable it. You need to disable the module and remove its record manually from the system table or include a hook_uninstall function.

Looking for support? Visit the forums, or join #drupal-support in IRC.


clemens.tolboom’s picture

There is not much info about how tables should be named on a per module basis.

And how long the names should be. Especially when db_prefix is involved.

cntlscrut’s picture

mainly when i'm working with multiple tables that i create, i tend to name follow this pattern....


such that it's easier to see that the table is specific to that module. of course other modules can utilize the table. it's just makes things easier when it comes to debugging or troubleshooting, in that you know exactly what module that table came from.


jjweiner’s picture

I think to begin the table name with the module name is a good convention. Thus, the table name could be broken into two elements, separated with an underscore:

1) module name
2) table description

where the "table description" is indicative of what kind of data the table stores. This way, developers can get a sense of your module's table structure just by looking at the database schema. Drupal does this somewhat with its core installation tables, sush as: 'node_type' , 'term_hierarchy'. I have found many contributed modules' tables do a similar thing, such as 'workflow_access', 'tinymce_settings', 'biblio_author_index'.


jwilson3’s picture

Since hook_install is run only the very first time you install a module. You may consider putting code that needs be executed every time you enable the module in hook_enable.