diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
index 62ebfc2acaf..897df1dd01a 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -117,6 +117,13 @@ public class Base {
   List<Editor> editors = Collections.synchronizedList(new ArrayList<Editor>());
   Editor activeEditor;
 
+  private static JMenu boardMenu;
+  private static ButtonGroup boardsButtonGroup;
+  private static ButtonGroup recentBoardsButtonGroup;
+  private static Map<String, ButtonGroup> buttonGroupsMap;
+  private static List<JMenuItem> menuItemsToClickAfterStartup;
+  private static MenuScroller boardMenuScroller;
+
   // these menus are shared so that the board and serial port selections
   // are the same for all windows (since the board and serial port that are
   // actually used are determined by the preferences, which are shared)
@@ -552,6 +559,36 @@ protected boolean restoreSketches() throws Exception {
     return (opened > 0);
   }
 
+  protected boolean restoreRecentlyUsedBoards() throws Exception {
+    // Iterate through all sketches that were open last time p5 was running.
+    // If !windowPositionValid, then ignore the coordinates found for each.
+
+    // Save the sketch path and window placement for each open sketch
+    int count = PreferencesData.getInteger("last.recent_boards.count");
+    int opened = 0;
+    for (int i = count - 1; i >= 0; i--) {
+      String fqbn = PreferencesData.get("last.recent_board" + i + ".fqbn");
+      if (fqbn == null) {
+        continue;
+      }
+      //selectTargetBoard(new TargetBoard());
+    }
+    return count != 0;
+  }
+
+  /**
+   * Store list of sketches that are currently open.
+   * Called when the application is quitting and documents are still open.
+   */
+  protected void storeRecentlyUsedBoards() {
+    int i = 0;
+    for (TargetBoard board : BaseNoGui.getRecentlyUsedBoards()) {
+      PreferencesData.set("last.recent_board" + i + ".fqbn", board.getFQBN());
+      i++;
+    }
+    PreferencesData.setInteger("last.recent_boards.count", BaseNoGui.getRecentlyUsedBoards().size());
+  }
+
   /**
    * Store screen dimensions on last close
    */
@@ -1313,6 +1350,63 @@ public void rebuildExamplesMenu(JMenu menu) {
   private static String priorPlatformFolder;
   private static boolean newLibraryImported;
 
+  public void selectTargetBoard(TargetBoard targetBoard) {
+    for (int i = 0; i < boardMenu.getItemCount(); i++) {
+      JMenuItem menuItem = boardMenu.getItem(i);
+      if (!(menuItem instanceof JRadioButtonMenuItem)) {
+        continue;
+      }
+
+      JRadioButtonMenuItem radioButtonMenuItem = ((JRadioButtonMenuItem) menuItem);
+      if (targetBoard.getName().equals(radioButtonMenuItem.getText())) {
+        radioButtonMenuItem.setSelected(true);
+        break;
+      }
+    }
+
+    BaseNoGui.selectBoard(targetBoard);
+    filterVisibilityOfSubsequentBoardMenus(boardsCustomMenus, targetBoard, 1);
+
+    onBoardOrPortChange();
+    rebuildImportMenu(Editor.importMenu);
+    rebuildExamplesMenu(Editor.examplesMenu);
+    try {
+      rebuildRecentBoardsMenu();
+    } catch (Exception e) {
+      // fail silently
+    }
+  }
+
+  public void rebuildRecentBoardsMenu() throws Exception {
+
+    Enumeration<AbstractButton> btns = recentBoardsButtonGroup.getElements();
+    while (btns.hasMoreElements()) {
+      AbstractButton x = btns.nextElement();
+      if (x.isSelected()) {
+        return;
+      }
+    }
+    btns = recentBoardsButtonGroup.getElements();
+    while (btns.hasMoreElements()) {
+      AbstractButton x = btns.nextElement();
+      boardMenu.remove(x);
+    }
+    int index = 0;
+    for (TargetBoard board : BaseNoGui.getRecentlyUsedBoards()) {
+      JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, menuItemsToClickAfterStartup,
+              buttonGroupsMap,
+              board, board.getContainerPlatform(), board.getContainerPlatform().getContainerPackage());
+      boardMenu.insert(item, 3);
+      item.setAccelerator(KeyStroke.getKeyStroke('1' + index,
+         Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() |
+         ActionEvent.SHIFT_MASK));
+      recentBoardsButtonGroup.add(item);
+      boardsButtonGroup.add(item);
+      index ++;
+    }
+    boardMenuScroller.setTopFixedCount(3 + index);
+  }
+
   public void onBoardOrPortChange() {
     BaseNoGui.onBoardOrPortChange();
 
@@ -1406,9 +1500,10 @@ public void rebuildBoardsMenu() throws Exception {
     boardsCustomMenus = new LinkedList<>();
 
     // The first custom menu is the "Board" selection submenu
-    JMenu boardMenu = new JMenu(tr("Board"));
+    boardMenu = new JMenu(tr("Board"));
     boardMenu.putClientProperty("removeOnWindowDeactivation", true);
-    MenuScroller.setScrollerFor(boardMenu).setTopFixedCount(1);
+    boardMenuScroller = MenuScroller.setScrollerFor(boardMenu);
+    boardMenuScroller.setTopFixedCount(1);
 
     boardMenu.add(new JMenuItem(new AbstractAction(tr("Boards Manager...")) {
       public void actionPerformed(ActionEvent actionevent) {
@@ -1448,21 +1543,26 @@ public void actionPerformed(ActionEvent actionevent) {
       boardsCustomMenus.add(customMenu);
     }
 
-    List<JMenuItem> menuItemsToClickAfterStartup = new LinkedList<>();
+    List<JMenuItem> _menuItemsToClickAfterStartup = new LinkedList<>();
+    boardsButtonGroup = new ButtonGroup();
+    recentBoardsButtonGroup = new ButtonGroup();
+    buttonGroupsMap = new HashMap<>();
+
+    boolean hasRecentBoardsMenu =  (PreferencesData.getInteger("editor.recent_boards.size", 4) != 0);
 
-    ButtonGroup boardsButtonGroup = new ButtonGroup();
-    Map<String, ButtonGroup> buttonGroupsMap = new HashMap<>();
+    if (hasRecentBoardsMenu) {
+      JMenuItem recentLabel = new JMenuItem(tr("Recently used boards"));
+      recentLabel.setEnabled(false);
+      boardMenu.add(recentLabel);
+    }
 
     // Cycle through all packages
-    boolean first = true;
     for (TargetPackage targetPackage : BaseNoGui.packages.values()) {
       // For every package cycle through all platform
       for (TargetPlatform targetPlatform : targetPackage.platforms()) {
 
         // Add a separator from the previous platform
-        if (!first)
-          boardMenu.add(new JSeparator());
-        first = false;
+        boardMenu.add(new JSeparator());
 
         // Add a title for each platform
         String platformLabel = targetPlatform.getPreferences().get("name");
@@ -1476,7 +1576,7 @@ public void actionPerformed(ActionEvent actionevent) {
         for (TargetBoard board : targetPlatform.getBoards().values()) {
           if (board.getPreferences().get("hide") != null)
             continue;
-          JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, menuItemsToClickAfterStartup,
+          JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, _menuItemsToClickAfterStartup,
                   buttonGroupsMap,
                   board, targetPlatform, targetPackage);
           boardMenu.add(item);
@@ -1485,14 +1585,16 @@ public void actionPerformed(ActionEvent actionevent) {
       }
     }
 
-    if (menuItemsToClickAfterStartup.isEmpty()) {
-      menuItemsToClickAfterStartup.add(selectFirstEnabledMenuItem(boardMenu));
+    if (_menuItemsToClickAfterStartup.isEmpty()) {
+      _menuItemsToClickAfterStartup.add(selectFirstEnabledMenuItem(boardMenu));
     }
 
-    for (JMenuItem menuItemToClick : menuItemsToClickAfterStartup) {
+    for (JMenuItem menuItemToClick : _menuItemsToClickAfterStartup) {
       menuItemToClick.setSelected(true);
       menuItemToClick.getAction().actionPerformed(new ActionEvent(this, -1, ""));
     }
+
+    menuItemsToClickAfterStartup = _menuItemsToClickAfterStartup;
   }
 
   private JRadioButtonMenuItem createBoardMenusAndCustomMenus(
@@ -1512,12 +1614,7 @@ private JRadioButtonMenuItem createBoardMenusAndCustomMenus(
     @SuppressWarnings("serial")
     Action action = new AbstractAction(board.getName()) {
       public void actionPerformed(ActionEvent actionevent) {
-        BaseNoGui.selectBoard((TargetBoard) getValue("b"));
-        filterVisibilityOfSubsequentBoardMenus(boardsCustomMenus, (TargetBoard) getValue("b"), 1);
-
-        onBoardOrPortChange();
-        rebuildImportMenu(Editor.importMenu);
-        rebuildExamplesMenu(Editor.examplesMenu);
+        selectTargetBoard((TargetBoard) getValue("b"));
       }
     };
     action.putValue("b", board);
@@ -1533,6 +1630,9 @@ public void actionPerformed(ActionEvent actionevent) {
     for (final String menuId : customMenus.keySet()) {
       String title = customMenus.get(menuId);
       JMenu menu = getBoardCustomMenu(tr(title));
+      if (menu == null) {
+        continue;
+      }
 
       if (board.hasMenu(menuId)) {
         PreferencesMap boardCustomMenu = board.getMenuLabels(menuId);
@@ -1595,13 +1695,13 @@ private static boolean ifThereAreVisibleItemsOn(JMenu menu) {
     return false;
   }
 
-  private JMenu getBoardCustomMenu(String label) throws Exception {
+  private JMenu getBoardCustomMenu(String label) {
     for (JMenu menu : boardsCustomMenus) {
       if (label.equals(menu.getText())) {
         return menu;
       }
     }
-    throw new Exception("Custom menu not found!");
+    return null;
   }
 
   public List<JMenuItem> getProgrammerMenus() {
diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java
index 0a58769712a..e0fa5f1d5e9 100644
--- a/arduino-core/src/processing/app/BaseNoGui.java
+++ b/arduino-core/src/processing/app/BaseNoGui.java
@@ -915,6 +915,12 @@ static public void saveFile(String str, File file) throws IOException {
     }
   }
 
+  static private LinkedList<TargetBoard> recentlyUsedBoards = new LinkedList<TargetBoard>();
+
+  static public LinkedList<TargetBoard> getRecentlyUsedBoards() {
+	  return recentlyUsedBoards;
+  }
+
   static public void selectBoard(TargetBoard targetBoard) {
     TargetPlatform targetPlatform = targetBoard.getContainerPlatform();
     TargetPackage targetPackage = targetPlatform.getContainerPackage();
@@ -926,6 +932,13 @@ static public void selectBoard(TargetBoard targetBoard) {
     File platformFolder = targetPlatform.getFolder();
     PreferencesData.set("runtime.platform.path", platformFolder.getAbsolutePath());
     PreferencesData.set("runtime.hardware.path", platformFolder.getParentFile().getAbsolutePath());
+
+    if (!recentlyUsedBoards.contains(targetBoard)) {
+      recentlyUsedBoards.add(targetBoard);
+    }
+    if (recentlyUsedBoards.size() > PreferencesData.getInteger("editor.recent_boards.size", 4)) {
+      recentlyUsedBoards.remove();
+    }
   }
 
   public static void selectSerialPort(String port) {