This page covers Drupal 6. For Drupal 7, please see Writing .install files (Drupal 7.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.

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.

As of Drupal 6.x the database tables are created using the Schema API .
The Schema API allows modules to declare their database tables in a structured array (similar to the Form API) and provides API functions for creating, dropping, and changing tables, columns, keys, and indexes.

A sample schema data structure (taken from the Schema Api Documentation)

As an example, here is an excerpt of the schema definition for Drupal's 'node' table:

 $schema['node'] = array(
    'description' => t('The base table for nodes.'),
    'fields' => array(
      'nid' => array(
        'description' => t('The primary identifier for a node.'),
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE),
      'vid' => array(
        'description' => t('The current {node_revisions}.vid version identifier.'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0),
      'type' => array(
        'description' => t('The {node_type} of this node.'),
        'type' => 'varchar',
        'length' => 32,
        'not null' => TRUE,
        'default' => ''),
      'title' => array(
        'description' => t('The title of this node, always treated a non-markup plain text.'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => ''),
      ),
    'indexes' => array(
      'node_changed'        => array('changed'),
      'node_created'        => array('created'),
      ),
    'unique keys' => array(
      'nid_vid' => array('nid', 'vid'),
      'vid'     => array('vid')
      ),
    'primary key' => array('nid'),
    );

In this excerpt, the table 'node' has four fields (table columns) named 'nid', 'vid', 'type', and 'title'. Each field specifies its type ('serial', 'int', or 'varchar' in this example) and some additional optional parameters, including a description.

The table's primary key is the single field 'nid'. There are two unique keys: first named 'vid' on the field 'vid' and second called 'nid_vid' on fields 'nid' and 'vid'. Two indexes, one named 'node_changed' on field 'changed' and one named 'node_created' on the field 'created'.

Creating tables: hook_schema and .install files

For the Schema API to manage a module's tables, the module must have a .install file that implements hook_schema() (note: in a pre-release version, hook_schema() was in a .schema file but that is no longer used.) For example, mymodule's mymodule.install file might contain:

function mymodule_schema() {
  $schema['mytable1'] = array(
     // specification for mytable1
  );
  $schema['mytable2'] = array(
     // specification for mytable2
  );
  return $schema;
}

function mymodule_install() {
  // Create my tables.
  drupal_install_schema('mymodule');
}

function mymodule_uninstall() {
  // Drop my tables.
  drupal_uninstall_schema('mymodule');
}

Updating your schema for new versions works just as it has since Drupal 4.7, using a hook_update_n() function. Suppose you add a new column called 'newcol' to mytable1. First, be sure to update your schema structure in mymodule_schema() so that newly created tables get the new column. Then, add an update function to mymodule.install:

function mymodule_update_1() {
  $ret = array();
  db_add_field($ret, 'mytable1', 'newcol', array('type' => 'int'));
  return $ret;

There is also a module available called as Schema Module which provides additional Schema-related functionality not provided by the core Schema API that is useful for module developers. Currently, this includes:

  • Schema documentation: hyperlinked display of the schema's embedded documentation explaining what each table and field is for.
  • Schema structure generation: the module examines the live database and creates Schema API data structures for all tables that match the live database.
  • Schema comparison: the module compares the live database structure with the schema structure declared by all enabled modules, reporting on any missing or incorrect tables.

Comments

r_honey’s picture

Schema API looks a good option for generating tables in a DB independent fashion. But I could not find solutions to some issues (like how to specify the Engine for MySql, or foreign key constraints or creating Stored Procedures & Functions).

Looks like this has to be done by getting a sql script executed. But the above doc does not detail how to get a Sql script executed during install/uninstall?

Can somebody document this aspect a bit??

m4manas’s picture

The hook_install is executing the schema built earlier. Once that is executed the control is handed over to what ever is the next fucntion. You can execute any sql code using drupal database api.

function mymodule_install() {
  // Create my tables.
  drupal_install_schema('mymodule');
  //run custom sql query
  db_query($sql, $parms);
}
JurriaanRoelofs’s picture

Interesting article about using an install file to store frontend interactions of a Drupal project:
http://sachachua.com/wp/2009/04/23/drupal-staging-and-deployment-tips-it...

-------------------------------
http://www.sooperthemes.com/#-Drupal-Themes

nimrod98’s picture

If you are writing the .install file LAST (ie after module has been activated), you need to make sure you disable the module and uninstall it first. Be careful though, as uninstalling removes everything in the table. Then by reactivating it, it should create the new table.

My suggestion before uninstalling is to rename the table name ie instead of 'node' name it to like 'node1'. You will get an error message, but at least it will not drop the entire 'node' table

ingo86’s picture

Sometimes however happens that you have already enabled a module and you wanna add later the .install file to it. This way you cannot uninstall it because there's nothing installed, but the system doesn't see your new .install file.

To quickly solve this issue delete the entry of your module inside the system table.

hermes_costell’s picture

More info on what to do if you're adding an .install file to an already enabled module that didn't previously have an .install file:

The SQL to delete the entry in the system table for your module will be like:
delete from `YOUR_DB_NAME`.`system` where name like 'YOUR_MODULE_NAME'

You will need to do this even if you disable the module and delete the files from the server (again - in the case that you enabled a module that had no .install file and want to add one after the fact).

So the steps you'll need to take are:

  1. disable the module
  2. delete the module files from the server
  3. delete the entry in the system table (code above)
  4. upload the module files (which includes your .install file of course)
  5. enable the module

After doing the above you should be able to use the uninstall method mentioned above to make changes to your .install file.

Heads-up: Drupal 7 will reach its End of Life on February 30th, 2517.

shabana.navas’s picture

What a life-saver! The directions really saved me loads of time.

Shabana Navas
snavas@acromedia.com
Software Developer
Acro Media
https://www.acromedia.com
1-800-818-4564
Skype: super.shaba

kovacsaba’s picture

I've spent an afternoon with this issue.

dashohoxha’s picture

Also if .install file is changed (which may be frequent in early development phases), it will be ignored, unless the module is removed from the table `system`. I guess that this is a problem encountered by all module developers (I have spent two days with it), so it should be included somewhere in the documentation, and even emphasized. Or better yet, provide an easy solution for developers (for example in the Devel module). Modifying the table `system` manually seems a bit tricky to me.

ibnkhaldun’s picture

If you need to make changes. The best idea is to implement hook_update_N() functions. Note the plural. You can write several functions as
sample_module_update_6100(){/*...*/}
sample_module_update_6102(){/*...*/}
sample_module_update_6103(){/*...*/}
or
sample_module_update_7100(){/*...*/}
...
all of them living in the same .install file

see: Updating tables: hook_update_N() functions

kendre_paresh’s picture

thanks dude, the uninstall thing really help me :)
I had tried enable and disable several time but got success in module uninstall and then enable sequence.

thank you :)

knightnet’s picture

The uninstall could do a SQL dump/export of the tables to a SQL file. That way you can recover if needed.

In fact, if your module creates custom node types, it may be worth having a feature to dump all nodes of that type when uninstalling - separately to the schema, etc. You can even write an optional load feature into the install so that data and settings can be independently re-installed.

hayskelly’s picture

I just wanted to say thanks, I have trying to figure out why my table wasn't being created. I just needed to uninstall it first.

Mark Vincent Verallo’s picture

Hi everyone, I want to support multi-site setup for my module. Is there a function to get
the current db_prefix? In Drupal 6 I can use global $db_prefix within a hook
but in Drupal 7 it's blank. I want to use db_prefix in hook_schema in Drupal
7. Any function or variable that holds the prefix?

Mark Vincent Verallo’s picture

I've just realized that I don't have to worry about the prefix within the hook_schema. Drupal will handle this!

Mark Vincent Verallo’s picture

There's nothing to worry about $db_prefix in the hook_schema because Drupal 7 will automatically handle the prefix of the current Drupal site. However, I want to use $db_prefix in another hook and other functions. What's the function for getting the prefix? I know that we can get it from the globals $databases['default']['default']['prefix'] but I don't like to use that.

theodorus’s picture

Is there any way to make the _install fail, for instance when a query fails or some other error occurs during installation, resulting in the module not being installed and an error message shown?

michaelfavia’s picture

Your hook_schema should always return the updated schema. In other words: If you add a table in hook_update_N, also add it to hook_schema.

slippast’s picture

For those who using Drupal 7 but following this guide you may be seeing this error when your module installs: DatabaseSchemaObjectExistsException: Table already exists

The Drupal 7 page describing how to build .install files recommends coming to this page (originally for the D6 version) for instructions. One big difference is that there's no need to use the drupal_install_schema function. Drupal will automatically install the schema you've defined, so calling the install function is basically trying to install the database twice.

I hope that helps someone.

ibnkhaldun’s picture

Hi there is a warning doc on this issue:
Updating tables: don't use hook_schema()

Read it!!

bdalhatu’s picture

I have created a custom table within a module for a content type which was created. I was able to add content and when I search the node table I could find the nid and the vid fields. How do i find other fields in the custom table, please assist.

april26’s picture

The .install file for the Conference module doesn't work - it is a D5 module and was not fully updated for D6 it seems. If you create the tables in MySql it works perfectly, so I just want to fix the .install file. This is what I have written, but I get an error message on Function conference_install.

As this was a D5 module, I dont know if another file can be influencing this installation.

<?php
function conference_schema() {
$schema['conference'] = array(
    'description' => t('The base table for conference.'),
    'fields' => array(
      'pnid' => array(
        'description' => t('The primary identifier for a conference.'),
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE),
      'pvid' => array(
        'description' => t('The current {node_revisions}.vid version identifier.'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0),
      'ruid' => array(
        'description' => t('RUID'),
        'type' => 'int',
        'length' => 10,
        'not null' => TRUE,
        'default' => '0'),
      'rnid' => array(
        'description' => t('RNID'),
        'type' => 'int',
        'length' => 10,
        'not null' => TRUE,
        'default' => '0'),
      'comment1' => array(
        'description' => t('Comment for Organiser only.'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => ''),
      'comment2' => array(
        'description' => t('Comment for Author.'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => ''),        
      'status' => array(
        'description' => t('The Status.'),
        'type' => 'int',
        'length' => 10,
        'not null' => TRUE,
        'default' => '0'),
     ),   
    'primary key' => array('pnid','ruid','pvid'),
);

$schema['conference_decision'] = array(
    'description' => t('The acceptance of the paper.'),
    'fields' => array(
      'pnid' => array(
        'description' => t('The primary identifier for a decision.'),
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE),
      'decision' => array(
        'description' => t('Type of Decision (abstract or full paper).'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0),

      'feedback' => array(
        'description' => t('Feedback for decision.'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => ''),
),   
    'primary key' => array('pnid'),

);
return $schema;
}
/*
* Implementation of hook_install()
*/

function conference_install() {
  // Create my tables.
  drupal_install_schema('conference');  // I get an error 'unexpected T_STRING, expecting ')' in ..conference\conference.install' 
}

function conference_uninstall() {
  // Drop my tables.
  //
  //
  //
  drupal_uninstall_schema('conference');
}
?>

There are 10 kinds of people in the world, those who understand binary and those who don't!
InterComm South Africa (www.intercomm.co.za)

april26’s picture

The code colouring after I posted this identified a missing quote mark on line 75, and it works now. I'll post it in the conference module as it may help others who also want this module. It has a very specific function - to allow University research abstracts and papers to be reviewed.

There are 10 kinds of people in the world, those who understand binary and those who don't!
InterComm South Africa (www.intercomm.co.za)