Last updated May 6, 2015. Created on March 4, 2014.
Edited by moshe weitzman, tstoeckler, Kristen Pol, amool. Log in to edit this page.

This article is being written based on the Spark distribution.

Installation profiles are like modules

All installation profiles must have:

  2. profilename.profile

files, and they can also have a profilename.install file.

The profilename.profile file has access to almost everything a normal Drupal modulename.module file does because Drupal is fully bootstrapped before almost anything in the profile runs. Profile files should reside in their own directory within the /profiles directory to be loaded.

.info.yml file

The file should look similar to this:

name: Profile Name
type: profile
description: 'Description of your profile.'
core: 8.x

# Optional: Declare your installation profile as a distribution
# This will make the installer auto-select this installation profile.
# The distribution_name property is used in the installer and other places as
# a label for the software being installed.
  name: Distribution Name

# Required modules
  - node
  - history
  - block
  - breakpoint
  - color
  - config
  - comment
  - contextual
  - contact
  - custom_block
  - edit
  - help
  - image
  - menu
  - number
  - options
  - path
  - taxonomy
  - dblog
  - responsive_preview
  - search
  - shortcut
  - toolbar
  - overlay
  - field_ui
  - file
  - rdf
  - views
  - views_ui
  - editor
  - ckeditor

.install file

* @file
* Install, update and uninstall functions for the spark install profile.

* Implements hook_install().
* Perform actions to set up the site for this profile.
* @see system_install()
function spark_install() {
  // First, do everything in standard profile.
  include_once DRUPAL_ROOT . '/core/profiles/standard/standard.install';
  // Can add code in here to make nodes, terms, etc.

.profile file

* @file
* Enables modules and site configuration for a standard site installation.

// Add any custom code here like hook implementations.

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


Berdir’s picture

st() no longer exists in Drupal 8, just use t().

I recommend using for creating default content in 8.x. But note that happens after hook_install(), so you can't refer to it there. I recommend to put it in a separate module that the install profile depends on.

loophole080’s picture

I'm fiddling with D8 profile building and figured I'd leave some feedback here as the docs are a little on the sparse side! :-) So...

Observation 1:

"All installation profiles must have:

This is not actually true as of D8 beta 15, all you really need is the info.yml file (the Minimal profile doesn't even have a .profile file!).

Observation 2:

Be aware that whatever you specify in the info.yml file will become fixed dependencies. In other words it is not possible to disable module declared by a profile's info.yml file. (So if you build from Standard profile you will be stuck with Tour, History, etc, which may not be desirable.) I'm looking into how to install modules in the profile without them being requirements.

Observation 3:

Most of the config work can be done using the new config management system (i.e. via .yml settings files - which is way easier than having to figure out a variety of different hooks to apply things like roles, permissions, module settings etc.) although you can also use hooks in the .install file. Standard profile seems to use a mix of both, not sure why but will report back findings here.

Observation 4:

Missing/unknown (or mis-spelled) modules in the info.yml cause a fatal error: "Fatal error: Call to a member function getPath() on a non-object in /[MY_SITES]/[DRUPAL_ROOT]/core/includes/ on line 920".

In other words, missing modules are not handled very elegantly and so be careful to watch for dependencies and typos. (Contrast to D7 profiles, where any missing/unknown modules would be flagged up as missing on the Verify Requirements page of the installer, much more forgiving!)

However, if a module requires another module (e.g. Views UI requires Views) and you have not listed it, the installer will automatically enable the required modules, as per normal.

Observation 5:

Right, this one had me puzzled for a while... While you can enable the devel module and kint submodule (to get debug output) to inspect the Configure Site form, don't bother, it can't handle the form!

Because of the regional settings the form array is RIDICULOUSLY big.... When I finally resorted to print_r() it outputs 138154 lines! Almost all of which is in ['regional_settings']['default_country']['#options'] and ['regional_settings']['date_default_timezone']['#options'].

I will post an abbreviated form output on my blog soon, in the meantime if you want to start messing with the Configure Site form, stick this in your .profile file (and set aside a few hours for scrolling!):

 * @file
 * Enables modules and site configuration for the MY_PROFILE site installation.

use Drupal\Core\Form\FormStateInterface;

 * Implements hook_form_FORM_ID_alter() for install_configure_form().
 * Allows the profile to alter the site configuration form.
function MY_PROFILE_form_install_configure_form_alter(&$form, FormStateInterface $form_state) {
// this print_r() will break the installer, so just use it for development when reloading the configure site form
  echo '<pre>';
  echo '</pre>'; 

Observation 6

We're back on familiar ground tweaking the installer forms as the Form API is essentially the same as in D7 (phew!). The two hooks you may need are MY_THEME_form_install_settings_form_alter() and MY_THEME_form_install_configure_form_alter(). I use my profile for iterative development, so it gets auto-installed repeatedly (using Behat/Selenium) and it's nice to have default values filled in on these forms, I also like to clear up some of the superfluous description text and change some headings.

If you decide you want to preset any of the values of the installer forms using the above alter hooks here's a couple of gotchas:

a) the settings form (aka "Database Configuration") needs to take plain old strings, you should not use t() for these values (the script that builds the settings.php file doesn't like translation)
b) unlike in D7, you can't set the value for password fields, which I assume is a security feature

Observation 7

OK we also still have the hook_install_tasks() and hook_install_tasks_alter() (which should live inside your .install file), which work similarly to in D7. However, we need to build any custom forms using the new D8 Form API Symphony-esque way of doing this (good, quick how-to here: and then use that form's proper class name in the tasks array, this will automagically load the form.

For example, in your .install file:

function MY_PROFILE_install_tasks(&$install_state) {
  // prepare to add extra install task steps for custom configuration
  $tasks = array();
  // add our custom configuration form to the install tasks 
  $tasks['Drupal\MY_PROFILE\Form\CustomConfigForm'] = array(
    'display_name' => t('Custom Config for MY_PROFILE'),
    'type' => 'form', 

This would load a corresponding form of class "CustomConfigForm" which would live in the file MY_PROFILE/src/Form/CustomConfigForm.php and look something like this:

 * @file
 * Contains \Drupal\MY_PROFILE\Form\CustomConfigForm 
namespace Drupal\MY_PROFILE\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
 * Implements custom config form for MY_PROFILE
class CustomConfigForm extends FormBase {
  public function getFormId() {
    return 'custom_config_form';
  public function buildForm(array $form, FormStateInterface $form_state) {
    // build your form here to do custom stuff
    return $form;
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // custom submit handler code here