I have just inherited a site to maintain.

The site has many pages ending with /node/$nid. I notice that appending /x to the end of this URL seems to change nothing. That is, if I browse to http://example.com/node/123/1, I get the same result as if I browse to http://example.com/node/123/2.

What are those numbers typically used for? I notice that in my sidebar, it seems to be sending people to the /2 version.

2 Answers 2


Drupal's path-matching is greedy. The path node/%nid will match anything with that string at the start, that has a separator after it. e.g

  • node/%nid/1
  • node/%nid/giraffe
  • node/%nid/barack-obama
  • node/%nid/this/is/just/too/much

The 'extra' path segments are passed on as extra parameters to the item's page callback, whether it wants/uses them or not.

The page that you see at node/%nid/1 isn't different at all from the standard node/%nid page.

You'd do well to keep those URLs out of the page source at all costs, or make sure you have an appropriate canonical URL set, as Google will consider them duplicate content otherwise.


That is the behavior of Drupal: When a module doesn't define a menu path matching the URL passed to Drupal, Drupal uses the closer menu path defined by a module. That behavior is caused by menu_get_item(), which contains the following code.

$parts = array_slice($original_map, 0, MENU_MAX_PARTS);
$ancestors = menu_get_ancestors($parts);
$router_item = db_query_range('SELECT * FROM {menu_router} WHERE path IN (:ancestors) ORDER BY fit DESC', 0, 1, array(':ancestors' => $ancestors))->fetchAssoc();

In your case, the closer menu path matching the URL you are using is node/%nid, which shows the node content. If you would use http://example.com/node/123/edit, the matching path would be node/%nid/edit, which shows the node edit form.

A module implementing hook_menu_get_item_alter() could easily change that behavior, since menu_get_item() contains the following code.

if ($router_item) {
  // Allow modules to alter the router item before it is translated and
  // checked for access.
  drupal_alter('menu_get_item', $router_item, $path, $original_map);

  $map = _menu_translate($router_item, $original_map);
  $router_item['original_map'] = $original_map;
  if ($map === FALSE) {
    $router_items[$path] = FALSE;
    return FALSE;
  if ($router_item['access']) {
    // …

  // …

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.