Last updated June 16, 2015. Created on October 4, 2010.
Edited by SebCorbin, Cottser, Heine, chrisjlee. Log in to edit this page.

"Render Arrays" or "Renderable Arrays" are the building blocks of a Drupal page, starting with Drupal 7. A render array is an associative array which conforms to the standards and data structures used in Drupal's theme rendering system.

In many cases, the data used to build a page (and all parts of it) is kept as structured arrays until the rendering stage in the theming system. This allows enormous flexibility in changing the layout or content of a page, and provides future performance enhancements as well.

Note: While render arrays and arrays used by the Form API share elements, properties and structure, many properties on form elements only have meaning for the Form API, not for the Render API. Form API arrays are transformed into Render arrays by drupal_get_form. Passing an unprocessed Form API array to the Render API may yield unexpected results.

What is "rendering"?

Rendering in the Drupal world means turning structured "render" arrays into HTML.

What is a render array?

A render array is a classic Drupal structured array that provides data (probably nested) along with hints as to how it should be rendered (properties, like #type). A page array might look like this:

$page = array(
  '#show_messages' => TRUE,
  '#theme' => 'page',
  '#type' => 'page',
  'content' => array(
    'system_main' => array(...),
    'another_block' => array(...),
    '#sorted' => TRUE,
  'sidebar_first' => array(
  'footer' => array(

Why was this done?

Before Drupal 7, we could alter things like forms (with hook_form_alter()), but so many other things that needed to be altered by a module or a theme had already been rendered into HTML before any rational thing could be done with them.

In Drupal 7 and later, a module or a theme can use hook_page_alter() to change the layout or content of the page at the very last moment. This means that a tidbit of PHP code in a theme can put that block over on the right side on one page when the customer needs it there.


Both blocks and pages can be altered just as forms have been alterable for some time. Many other types are also alterable. With hook_page_alter() both modules and themes can do things like this:

function mymodule_page_alter(&$page) {
  // Move search form into the footer.
  $page['footer']['search_form'] = $page['sidebar_first']['search_form'];
  // Remove the "powered by Drupal" block

How are Render Arrays Related to Elements?

Modules have the capability of defining "elements", which are essentially prepackaged default render arrays. They use hook_element_info() to do this. An element is essentially a prepackaged render array that has a #type and some other properties. When #type is declared for a render array, the default properties of the element type named are loaded through the use of hook_element_info().

Creating Content As Render Array

Unlike in past versions of Drupal, almost any time a module creates content, it should be in the form of a render array. A page callback should return a render array, as should hook_block_view()'s $block['content']. This allows your module and other modules to treat the content as data for as long as possible in the page generation process.

So a page callback might return this instead of the Drupal 6 method of rendering the data and gathering it as HTML:

function mymodule_menu() {
  $items['mypage-html'] = array(
    'title' => 'My page with HTML-style function',
    'page callback' => 'mymodule_html_page',
    'access callback' => TRUE,

  $items['mypage-ra'] = array(
    'title' => 'My page with render array function',
    'page callback' => 'mymodule_ra_page',
    'access callback' => TRUE,

  return $items;

// Previous method (still works) of generating a page by returning HTML
function mymodule_html_page() {
  $output = '

A paragraph about some stuff...

'; $output .= '
  • first item
  • second item
  • third item
'; return $output; } // New method of generating the render array and returning that function mymodule_ra_page() { $output = array( 'first_para' => array( '#type' => 'markup', '#markup' => '

A paragraph about some stuff...

', ), 'second_para' => array( '#items' => array('first item', 'second item', 'third item'), '#theme' => 'item_list', ), ); return $output; }

Examples of Specific Array Types

As in the past, every Drupal "element" (see hook_element_info(), which was hook_elements() in Drupal 6) is a type. So anything that core exposes as an element or that an installed module exposes is available. Looking through system_element_info() we see a pile of predefined #types, including page, form, html_tag, value, markup, link, fieldset and many more. By convention, the #-properties used by these #types are documented with the respective theme function. So you can find out the properties used by #type => 'html_tag' elements by checking out the documentation for theme_html_tag(). You can also create types and properties on the fly.

Here are three examples pulled from the Examples Project's Render Example.

$demos = array(
  t('Super simple #markup')  => array(
    '#markup' => t('Some basic text in a #markup (shows basic markup and how it is rendered)'),

  'prefix_suffix' => array(
    '#markup' => t('This one adds a prefix and suffix, which put a div around the item'),
    '#prefix' => '

', '#suffix' => '
', ), 'theme for an element' => array( 'child' => array( t('This is some text that should be put together'), t('This is some more text that we need'), ), '#separator' => ' | ', // Made up for this theme function. '#theme' => 'render_example_aggregate', ), );

A Sampling of Properties

Many, many properties can be applied in a given render array, and they can be created as needed. This will attempt to cover some of the most common.

Note that many of these properties are documented in the Form API Reference because the Form API has always used Render API properties, but they've traditionally not been documented as Render API properties, which they clearly are now in Drupal 7.

Property Description
#type The Element type. If this array is an element, this will cause the default element properties to be loaded, so in many ways this is shorthand for a set of predefined properties which will have been arranged through hook_element_info().
#markup The simplest property, this simply provides a markup string for #type => 'markup'
#prefix/#suffix A string to be prefixed or suffixed to the element being rendered
#pre_render An array of functions which may alter the actual render array before it is rendered. They can rearrange, remove parts, set #printed = TRUE to prevent further rendering, etc.
#post_render An array of functions which may operate on the rendered HTML after rendering. A #post_render function receives both the rendered HTML and the render array from which it was rendered, and can use those to change the rendered HTML (it could add to it, etc.). This is in many ways the same as #theme_wrappers except that the theming subsystem is not used.
#theme A single theme hook which will take full responsibility for rendering this array element, including its children. It has predetermined knowledge of the structure of the element. Note: #theme in Drupal 7 and #theme in Drupal 6 are not really related. If you just stop thinking about Drupal 6 here, you will have an easier time.

Basically, the '#theme' = 'function_name' calls theme_function_name(), and other array values of the form '#var_name' = $value in the same array are passed as arguments to the theme function.

There is a list of all the default theme hooks at

#theme_wrappers An array of theme hooks which will get the chance to add to the rendering after children have been rendered and placed into #children. This is typically used to add HTML wrappers around rendered children, and is commonly used when the children are being rendered recursively using their own theming information. It is rare to use it with #theme.
#cache Mark the array as cacheable and determine its expiration time, etc. Once the given render array has been rendered, it will not be rendered again until the cache expires. Caching uses standard Drupal cache_get() and cache_set() techniques. This is an array of
  • 'keys' => an array of keys which will be concatenated to form the cache key.
  • 'bin' => the name of the cache bin to be used (as in 'cache' or 'cache_page', etc.
  • 'expire' => a Unix timestamp indicating the expiration time of the cache.
  • 'granularity' => a bitmask indicating the cache type. This should be DRUPAL_CACHE_PER_PAGE, DRUPAL_CACHE_PER_ROLE, or DRUPAL_CACHE_PER_USER

Note that items marked with #cache will not be expired until cron runs, regardless of the expiration time used.

#weight Set a weight to the child. Children will be automatically sorted on rendering, with the function drupal_sort_weight().

Since every element type can declare its own properties, there are many more. Many of these (often specific to a particular element type) are described on the Form API Reference handbook page.


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


slite’s picture

Examples has been reorganised in git and source code link is now:

(Now changed above)

Mark_L6n’s picture

It should be mentioned that render arrays for forms are different from other render arrays.
Render arrays for forms can only be created in modules (not in tpl.php files) and are not rendered with render().

stickywes’s picture

This is not entirely incorrect. A form eventually makes its way through drupal_render(), which is getting called when you call render(). The form API just has to do a lot of extra work to transform a basic form array you might build in a module into something that will function or look correct (see: drupal_process_form).

technicalknockout’s picture

To turn a node object into a render array use the node_view function:

function mymodule_callback($node) {
  $node_render_array = node_view($node);
  return array(
    'stuff' => array('#type' => 'markup', '#markup' => 'Here Is Some Stuff'),
    'node' => $node_render_array,
    'more_stuff' => array('#type' => 'markup', '#markup' => t('Here Is Some More Stuff')),

- - - -

charlie-s’s picture

I think the #cache portion of this doc should be updated to include the fact that #pre_render is required to actually gain any benefit from using the #cache.

nyl_auster’s picture

I think the #cache portion of this doc should be updated to include the fact that #pre_render is required to actually gain any benefit from using the #cache.

hell yeah, i had to read code from module examples to understand that.
I'm sad to see that this #cache property is able to specify a "time to live" (expiration date) property; and that blocks can't do the same thing in drupal 7...

and 'im not sure that i want to code every time a #pre_render to use benefits of #cache property :-/

Baysaa’s picture

You guys are free to update the documentation though.

bkline’s picture

Using render arrays for page callbacks won't always do what you expect them to. For example,

function my_page_callback() {
    return array(
        '#type' => 'container',
        '#attributes' => array(...),
        'first' => array(...),
        'last' => array(...));

will not result in having your markup wrapped in a div element as you would expect. I think I'm beginning to understand why much of Drupal core bypasses the use of render arrays. :-)

Jaypan’s picture

#type only exists if your render array is passed through drupal_get_form() - i.e. form elements. This is why you aren't seeing what you are expecting. You *could* pass your array through drupal_get_form() before rendering it, but it would be a bit of overkill just to get a container out of it.

The Drupal organization has shut down discussion on improvement of the forums:

It's time to start a new forum somewhere else. The Drupal organization does not care about the forums.

Jaypan’s picture

A little more information on using render arrays in page callback functionss:

The Drupal organization has shut down discussion on improvement of the forums:

It's time to start a new forum somewhere else. The Drupal organization does not care about the forums.

qqboy’s picture

There s a type page but not definition of this type in form api
But you said type only valid as defined in form api
Could you please tell us a little bit more about it
Thanks .....

thank you.

Henrik E Bechmann’s picture

With lots of software dev experience, but little Drupal experience, here's my take:

The assembled collection of render arrays, culminating in $page, is a classic Data Model consisting of (as we know) nested arrays. Each of these nested arrays is an Abstract Data Type often (but not always) identified by its "#type" property. Each abstract data type consists of properties ("#"-prefixed) and data (non-"#"-prefixed).

In a more general sense, I see Drupal as a dispatch-driven state change machine with a service-oriented architecture. The state change machine through its service calls to modules (aka "hooks") alters (parts of) the data model in progressive stages through the life cycle of a website request, until the data structure conforms to a renderable structure - hence the name "renderable". But it's important to note that some of the data doesn't start out as renderable. For an example, follow the stages of transformation of $user data to user->content and finally the &$build (renderable) structure.

Jaypan’s picture

That's pretty accurate.

The Drupal organization has shut down discussion on improvement of the forums:

It's time to start a new forum somewhere else. The Drupal organization does not care about the forums.

Henrik E Bechmann’s picture

Here's the more closely defined meaning of "renderable":

From the source code of theme():

// If a renderable array is passed as $variables, then set $variables to
  // the arguments expected by the theme function.
  if (isset($variables['#theme']) || isset($variables['#theme_wrappers'])) {
    $element = $variables;
    $variables = array();
    if (isset($info['variables'])) {
      foreach (array_keys($info['variables']) as $name) {
        if (isset($element["#$name"])) {
          $variables[$name] = $element["#$name"];
    else {
      $variables[$info['render element']] = $element;

This means that a "renderable array" includes a "#theme" or "#theme_wrappers" property. Also if the theme has been defined with variables, a renderable array includes a property for each defined variable, ie "#$varname".

So as an example here's a renderable array. Note that the top level data values are properties, prefixed with a "#".

  "#account"=> array("path"=>"/account/1","name"=>"Bigstuff Retailers (Toronto)"),
  "#affiliate"=> array("path"=>"/affiliate/2","name" => "Downtown Toronto Outlet"),

... based on this theme definition:

'customer-subtitle' => array(
	'template' => 'customer-subtitle',
	'variables' => array(
		'account' => array(),
		'affiliate' => array(),
		'location' => array(),
		'staff' => array(),

#account and #affiliate are actually data, not control or meta properties, and will end up as $account and $affiliate variables in the template.

ranelpadon’s picture

Thanks for these valuable info, just what I need: account variable in the theme definition corresponds to the #account data in the theme invocation (when used alongside with the #theme property).

qqboy’s picture

This seems hard to understand could you please to give me a link with more explaination ? Thanks a lot lot.

thank you.

holyfire’s picture