Skip to main content
ButterCMS Collections are a great fit to store navigation menu data, as they’re both flexible and restricted to simple data types. With a ButterCMS Collection, you can also:
  • add logos and images
  • enforce validation for strings, numbers, and URLs
  • nest multiple levels of navigation
For a full breakdown of ButterCMS Collections, check out our core concepts article.

Modeling your menu in ButterCMS

Create a single level menu

Follow the below steps to create a simple, flat menu with the following hierarchy:

Main menu
Home
About
Features
Try it
Testimonials
Blog
1

Create the Menu Item Collection

First, build the schema for your menu items. Important fields include:
  • Label - The display text
  • URL - What the item links to
Navigation Menu Item collection schemaSave it as “Navigation Menu Item”:Save as Navigation Menu Item
2

Create the Parent Menu Collection

Need more features than Collections allow? You can also use a Page to hold the Reference fields for your menu items.
Create a second Collection for the main menu that references the menu items:
  • Name - The navigation menu name
  • Menu Items - A Reference field linking to Navigation Menu Item (One-to-Many)
Navigation Menu with reference field
3

Add Menu Items

Click New item to add items to your Collection:Add new item buttonAdd each navigation item with its label and URL:Navigation Menu Item entry
4

Link Items to the Menu

In your main Navigation Menu, click Add Reference and select all the items you want:Linking menu items via reference

Building a complex multi-level menu

For complex menus with multiple levels, create separate Collections for each level. Here’s an example hierarchy: Complex multi-level navigation menu
1

Create third-level collection

Start with the lowest-level children. Create “Menu - Third Level”:Third level menu item schemaSave as Menu Third Level
2

Create second-level collection

“Menu - Second Level” includes a Reference field linking to Third Level:Second level with reference to third
3

Create first-level collection

“Menu - First Level” references Second Level:First level with reference to second
4

Populate the collections

Add items to each level:Third Level:Third level menu itemsSecond Level:Second level menu itemsFirst Level:First level menu items
5

Link collections together

Use the Add Reference button to connect items from one Collection to another:Linking collections via reference

Common navigation patterns

Fetching navigation via API

JavaScript/Node.js

const Butter = require('buttercms');
const butter = Butter('your-api-token');

// Fetch navigation menu
const getNavigation = async () => {
  const response = await butter.content.retrieve(['navigation_menu'], {
    'fields.name': 'Main Menu'
  });

  return response.data.data.navigation_menu[0];
};

// Example response structure
{
  "name": "Main Menu",
  "menu_items": [
    { "label": "Home", "url": "/" },
    { "label": "About", "url": "/about" },
    { "label": "Features", "url": "/features" }
  ]
}

Multi-level menu fetch

const getComplexNavigation = async () => {
  // Fetch all levels with nested references
  const response = await butter.content.retrieve([
    'menu_first_level'
  ], {
    levels: 3 // Fetch nested references up to 3 levels deep
  });

  return response.data.data.menu_first_level;
};

React component

import { useEffect, useState } from 'react';
import Butter from 'buttercms';

const butter = Butter('your-api-token');

const Navigation = () => {
  const [menu, setMenu] = useState(null);

  useEffect(() => {
    const loadMenu = async () => {
      const response = await butter.content.retrieve(['navigation_menu'], {
        'fields.name': 'Main Menu'
      });
      setMenu(response.data.data.navigation_menu[0]);
    };

    loadMenu();
  }, []);

  if (!menu) return null;

  return (
    <nav>
      <ul>
        {menu.menu_items.map(item => (
          <li key={item.url}>
            <a href={item.url}>{item.label}</a>
          </li>
        ))}
      </ul>
    </nav>
  );
};

export default Navigation;

Performance tips

For global API calls like header and footer navigation, cache the response. A cache duration of 5-10 minutes is typical, or use on-demand revalidation when content changes via webhooks.
  1. Cache navigation responses at the edge or in your app layer (5-10 minutes is typical).
  2. Use levels sparingly to avoid oversized responses for deep menus.

Best practices

Content modeling
  1. Separate concerns: Use different Collections for header vs footer
  2. Include icons: Add optional Media fields for menu item icons
  3. Support external links: Include a checkbox for “Open in new tab”
  4. Add ordering: Use a Number field if you need custom sort order
Accessibility
  1. Use semantic HTML: <nav>, <ul>, <li> elements
  2. Add ARIA labels: aria-label, aria-expanded for dropdowns
  3. Keyboard navigation: Ensure all items are focusable
  4. Mobile considerations: Include hamburger menu for small screens