Generating and Understanding a New Project

What you’ll learn and how you can apply it

By the end of this section, you’ll be able to:

And you'll be able to:


Astro comes with a "generator script" that you can run to start your project. It’s designed to give you an "out-of-the-box" experience that will meet most of your needs early in a project. By standardising the structure of an app, it not only makes picking up another Astro app easier but also provides new developers with a structured and educational foundation to start from.

image alt text Figure 1. The Welcome Screen, Home Screen and Flyout Drawer of a newly generated project.

The Generator Script

Visit the Astro Generator Github project to get the generator script (shown below). You can run the generator script to create a new project. Follow the instructions on your screen.

$ bash <(curl -s

image alt text Figure 2. The Generator Script.

Steps in the generator:

  1. Read the licence agreement by choosing "y".

    • Once you read the licence, press "q" to close the licence screen and then press "y" again to confirm.
  2. Give your app a project name.

    • We encourage you to use the proper capitalization when giving your project a name. Astro will downcase the name where appropriate in the project.
  3. Set your Android deep linking URL.

    • Whenever the user navigates to this URL (whether it’s from an email or text message), Android can intercept the URL and ask the user if they would rather open the URL in the app. Be sure to include the subdomain (ex: www or store) and top-level Internet domain (ex: com or

      For example: or

  4. Set your bundle identifier & package name.

    • This is the internal ID that either Apple or Google will use to reference your app. We encourage you to stick to the com.[company-name].[app-name] structure. (ex: com.mobify.veloapp).
  5. Choose if you want continuous integration.

    • If you’re just quickly building a prototype app (which is the case for most examples in this learning content), you will not need continuous integration.

    • Astro ships with support for building on BuddyBuild. BuddyBuild is an awesome continuous integration and delivery platform that is tailored for mobile apps. BuddyBuild provides delivery features that relieve you, the app developer, of having to manage all the details of the platform deployment ecosystem (such as signing certificates and provisioning profiles) and instead focus on building your app.

  6. Choose tab bar or flyout drawer navigation - you can choose whether you want to use the drawer or tab bar for your app’s main navigation. There are considerations to choosing either approach:

    • Drawer: Using a flyout menu drawer is the standard navigation pattern in Android and is the easiest to manage and build your app. This is because there is only one main view at all times (compared to multiple open views when using the tab bar approach).

    • Tab Bar: While the tab bar provides a better user experience it can be much more complicated to manage because of the extra work required to manage state across multiple open views (ex: "favoriting" a product may mean you need to refresh the "wishlist" tab in your app).

NOTE: Regardless of which navigation pattern you choose, deciding to use different approaches for iOS and Android can become difficult to manage because you will have two different navigation paths to maintain. It’s possible to use different approaches for iOS and Android (e.g. the Ritchie Brothers iOS app uses tab bars and the Android app uses a flyout drawer), but it will be more work. Ideally, you should stick to one navigation pattern at first and decide whether you wish to use a different navigation pattern after your apps have been published.

Once you’ve completed the generator script it will configure your app. To see what you generated, open the project by running the code below. (Replace appName with the name you picked for your project when you ran the generator script above).

$ cd appName
$ open ios/appName.xcworkspace

Then build and run the project. Once you’ve waited for your project to build, it will open in the simulator to the Welcome Screen shown below:

Figure 3. The Welcome Screen when your app loads for the first time.

Understanding the Project and What's Included

The generated project comes with a number of features baked in that are ready to configure. The main features to know about are:

  1. A welcome screen to show a user the first time they open the app.
  2. Search dropdown to help users search your app (by using your desktop site’s search functionality).
  3. A shopping cart view that takes takes over the app experience so a shopper can checkout.
  4. A flyout menu that can have nested menu items and can be customized using HTML and CSS.
  5. Deep linking support to open the app to the correct url opened from another app.
  6. Error screen to let the user know that there was a problem or that they might not have internet access.

Where possible, we’ve included configuration files to help with the centralization of app styling and content customization:

Project Structure

The three main folders found in your app projects are:

  1. /app - This folder contains most of the code you will write. It includes app.js and other JavaScript, HTML and CSS files you write. The contents of this folder are made available to both the Xcode and Android Studio projects.
  2. /ios - This folder contains your Xcode project file and necessary Swift code.
  3. /android - This folder contains your Android Studio project file and necessary Java code.

Understanding the files and folder under /app folder:

Welcome Screen

The Welcome Screen is a great way to greet your users the first time they load your app. It can be used to show a tutorial, login screen, or just a friendly greeting.

The Welcome Screen is an HTML view that you can edit. We encourage you to always bundle the HTML file of the Welcome Screen with your app since it will be presented faster and will work when the user opens the app when they’re offline (otherwise it may lead to a poor user experience). Optionally, you can include a native header bar. This can be useful if you want users to be able to navigate to another screen but remain in the modal view. For example, navigating to a sign up screen from the Modal View.

The Welcome Screen header bar can also be styled. You can change the title and background color. For example: you can make the Welcome Screen be a sign-in screen. (More on this below in the "Header Bar" sub-section).

NOTE: Apple does not allow shopping apps that require signing-in to be useable. A common pattern is to make the welcome screen be the sign in screen, but also dismissable so that a user can close the view and look around the app.

Figure 4. Welcome Screen with a Native Header Bar.

Header Bar

Most mobile apps include a header bar in their design. On iOS you might know this as a navigation bar and on Android it is referred to as a toolbar.

Astro provides a HeaderBarPlugin to present this common design pattern in your Astro app. The generator uses the header bar in both the welcome screen and in the main app UI. The header bar provides context to inform the user what screen they're on and gives access to some of the most-used actions. It also gives the user a way to navigate back via a back button.

Where are the files located?

You can customize the header bar for the welcome screen and the main UI. To customize the welcome screen header bar edit app/app-config/welcomeConfig.js. Customizations for the main UI header bar are done in app/app-config/headerConfig.js.

What can you change?


Any of the values in this file can be changed to customize the header bar of your welcome screen. You can customize:


The generator provides for a title and 3 icons in the header bar out of the box: one on the left and two on the right, as shown in the screenshot below:

image alt text

Figure 5. Header Bar icons (iOS left, Android right).

You can customize the title in the header bar using the cartTitleHeaderContent structure. The icons can be used for whatever your design calls for, but in the generator they are referred to (from left-to-right) as the "drawer" (drawerHeaderContent), "search" (searchHeaderContent), and "cart" (cartHeaderContent).

   [Drawer]    Center Title   [Search] [Cart]

NOTE: You will only see the drawer icon if you decided to not use tabs when running the project generator.

You can change the icon image by overwriting the image asset referenced in the headerConfig.js file in the native projects (iOS and Android).

Adding a logo

The Astro header bar supports using a logo in the center area instead of showing title text. In the welcomeConfig.js file edit the headerContent structure. In the headerConfig.js file edit the titleHeaderContent structure. In both cases you can use a logo by removing the title property of the structure and adding a new property named imageUrl. This new property should reference an image that you've added to each native project (eg. file:///icon__logo.png).

Best Practices

When customizing the icons, it is best not to change the id nor imageUrl values of the structures in either file. You can change the icon image by overwriting the native asset referenced by the imageUrl property with a new image file. Changing the id property will result in the click handlers breaking as they are bound using the id property of the header bar buttons.

Modal Cart

The generator comes with a modal popup to display the shopping cart. As with many things in an Astro app, this modal simply hosts a HeaderBarPlugin and WebViewPlugin. The WebViewPlugin is pointed to the cart page of your website. You can set the url for the shopping cart page of your site in app/app-config/cartConfig.js. Once you've done this you can run the app, tap the cart icon in the header, and you should see your shopping cart.

Figure 6. Opening the cart modal.

You can also configure the header bar for the cart modal within. You will notice that the way you customize the cart header bar is the same as the welcome screen and main app UI. You can customize the title text (or swap in an icon) and change the close icon just as with other header bars in the generator.

Flyout Drawer Navigation

A flyout drawer is a navigation pattern that provides the user a way to easily navigate around the app without the navigation taking up space in the main app UI permanently. If you do not enable tabs when generating your app, you will have a flyout drawer. To access it, tap on the left-most icon in the header bar (the drawer icon is commonly referred to as a "hamburger" icon because of the three horizontally-stacked lines).

This flyout drawer presents your app's main navigation menu. It hosts a WebViewPlugin which loads a locally bundled HTML file that represents your app menu items. We encourage using a locally bundled HTML file because it’s much faster to load and also works offline.

Menu Configuration

The menu structure is defined in app/app-config/menuConfig.js. This file contains a hierarchical JSON structure that defines how your app will look. Each object in the menu structure represents either a "leaf" element which will navigate the main UI or a sub-menu which will cause the menu to show the list of menu items in the sub menu.

Leaf elements always have a title and an href property. The title defines the text of the menu item. The href defines what url the main UI will navigate to when the user taps the item.

Sub-menu elements also have a title property, plus a list of sub-menu items which themselves are either leaf or sub-menu items named subItems. The menu structure can be arbitrarily deep, however we encourage you to simplify your menu structure as much as possible to make it easier on the end-user when navigating your app (otherwise they may experience "choice paralysis" because they are overwhelmed with the number of options and perceived size of the app).

Here's an example of how the menu structure looks. There are two top-level menu items. One is Home which navigates the user back to the root of the site. The other is Products which contains a sub-menu of one item, Bikes.

const menuItems = [
        'title': 'Home',
        'href': '/'
        'title': 'Products',
        'subItems': [
                'title': 'Bikes',
                'subItems': [
                    'title': 'Road Bike',
                    'href':  '/bikes/road-bike'

Advanced Customization

The menu configuration from app/app-config/menuConfig.js is rendered by JavaScript that comes with your generated app. As a result, you can customize exactly how your flyout menu looks and behaves. The rendering code for the menu can be found in app/app-www/js/left-drawer.js. This code, as it ships with the generator, simply iterates through the menu structure and renders out HTML elements for each item. It uses navitron to enable sliding navigation when navigating to sub-menus and back.

An example of some advanced customization is to include an imageUrl property for each menu item and then render them as tags in the HTML. This can be seen in action in the LDExtras app in Figure 7.

Figure 7. LDExtras app with custom menu icons.

Offline Screens

Newly generated Astro apps come with some basic error handling. If a webview takes too long to load (called a "page timeout") or fails to load because there’s no internet connection, the app will display a error modal with a short message. You can customize the message and image shown on the error screen by editing app/app-config/errorConfig.js. There is a single event that is handled in your generated app: pageTimeout. Within the pageTimeout event you receive a structure that has an error code and description. For each error code, you can customize the title, message, and imageUrl displayed when that error occurs.

You can test this by running the app on a real device, launching it, turning on Airplane Mode, and then tapping on a link. You will see the error modal appear with the error message.

Tab Bars

Tab bars a great way to provide quick access to the most important features of your app by making those features always accessible. The iOS Human Interface Guidelines provide a good set of guidelines for designing what you put in the tab bar. The generator provides for up to 5 tabs which can all be configured in app/app-config/tabConfig.js. Each tab is represented by a structure made up of the following keys:

The TabBarPlugin will automatically provide a highlighted look when the tab is selected and so for most cases you can use the same icon for imageUrl and selectedImageUrl. In some cases you might want to have a slightly different icon when it is selected in which case you can provide it via the selectedImageUrl property of that tab.

In Figure 8 you can see that on the left the rocket icon is the same when selected and when not (iOS automatically tints the icon to be blue when selected). On the right you can see the built-in Photos app actually uses different icons when the tab is selected (note that the icon is filled in when selected).

Figure 8*. Tab bar icons (left: same icon, right: custom selected icon).


The generated project uses a controller pattern to separate the application behaviour into multiple modules so that it is easier to maintain and modify. Controllers in an Astro app are simple JavaScript classes that own some part of the screen (they can also be "nonvisual" if they provide a service, such as "app review management", for example).



Controllers often have an associated config file that provide some control over their behavior (as you've already seen in previous sections of this lesson). The easiest way to check if a controller is already configurable is to look at the controller's code and see what modules it requires in. If you look at app/app-controllers/tabBarController.js you'll see that it requires in config/tabConfig. This shows you that the TabBarController can be configured to some extent by a configuration file. It's a good practice to get into separating configuration information from your code in this way.

View Plugins

In the generated project we follow a convention where each controller exposes a property named viewPlugin, if it can be integrated into the UI (for example, the TabBarController exposes a viewPlugin that contains the tab bar). This makes the rest of the code that deals with controllers more consistent as any time we want to put a controller's view into the view hierarchy we know that we can get it's top-level view by accessing the viewPlugin property.


Astro methods are asynchronous and as a result return a Promise instead of the actual method call result. Because of this, Astro plugins are always initialized asynchronously via an init() method (instead of using the new keyword). Controllers in Astro and the generated project follow this convention for a number of reasons and so when you initialize a controller you get a Promise back. You'll need to resolve that promise before you can use the controller. The easiest way is to call the then() method on the returned promise. Within the function you pass to the then() call you will get a reference to your ready-to-use controller.

const controller = await MyController.init();
// Use the controller here…


In this section you learned about how to generate a new Astro app using the Astro Generator. Once the app was generated you saw how the project is structured and where the important files can be found. Finally, you learned how to begin customizing the app to suit your project's needs. You should now feel comfortable with editing files in an Astro app and running it to see how it affects the app behaviour, look, and feel.


For more details you can view the detailed notes in the Astro Scaffold project found on Github.