Jigar KarangiyaJigar Karangiya
Articlebeginner45 minAdobe CommerceApp BuilderAIO CLIExtensibility

App Builder Console, AIO CLI, and your first Hello World app

· 15 min read

If you read the optional intro slide deck (opens in new tab) and still wonder where the code actually lives, this lesson closes that gap. We are not touching Commerce PHP yet. We are setting up Adobe Developer Console, installing the AIO CLI, scaffolding a tiny app, and deploying it to Adobe I/O Runtime.

That split matters. You own the Git repo. Adobe hosts the serverless runtime and the static web assets after you run aio app deploy. Confusing those two is how people end up looking for "App Builder hosting" in the wrong place.

Optional prerequisite: the What is Adobe App Builder? (opens in new tab) slide deck (5-minute conceptual overview).

Lesson checklist

This lesson maps to the App Builder first-app path in Adobe's docs. You should be able to do each item when you finish:

  • Explain Adobe Developer Console and the org → project → workspace hierarchy
  • Describe what you manage in Git vs what Adobe hosts after deploy
  • Install the AIO CLI, log in, and run aio update
  • Use aio where and the aio console * select commands to pick org, project, and workspace
  • Create a Console project from the App Builder template
  • Scaffold a Hello World app with aio app init --standalone-app
  • Bind a folder with aio app use and understand .aio and console.json
  • Generate and extend a local .env without committing secrets
  • Read app.config.yaml and know what the actions/ and web-src/ folders do
  • Run aio app dev locally, then aio app deploy, and open the deployed URL

Adobe Developer Console in plain terms

Adobe Developer Console (opens in new tab) is the control panel for App Builder projects. It is where you create projects, workspaces, API credentials, and event registrations. It is not where your source code lives.

Think of it in three layers:

Adobe organizes everything as Organization > Project > Workspace > [API or service]. The org is your company's IMS tenant. The project is the App Builder app bucket in Console. The workspace is the deploy target with its own Runtime namespace and credentials.

Every App Builder project gets two default workspaces: Production and Stage. You can add more (one per developer, or one per environment). Use Stage (or a personal workspace) for experiments. Adobe reserves the Production workspace for submission and distribution workflows when you ship an app to other orgs.

Each workspace has its own Runtime namespace and credential set. Credentials do not leak across workspaces.

When you open Console, check the IMS org switcher in the upper right. App Builder is licensed per org. If you pick the wrong org, the App Builder template simply will not show up under Quick Start, and you will waste twenty minutes blaming npm.

Common Console tasks for this lesson:

  • Quick Start → Create project from template → App Builder
  • Workspace overview → Download all (exports a JSON credential bundle for aio app use or --import)
  • Add API or Event registrations when a later lesson needs Commerce OAuth or I/O Events

Repository management: what you set up vs what Adobe runs

This trips up Magento developers because Commerce Cloud blurs the line between "your repo" and "where it runs." App Builder is clearer once you accept the split.

You set up manually:

  • A Git repository (GitHub, GitLab, Bitbucket, whatever your team uses)
  • Local Node.js tooling and the AIO CLI
  • The Developer Console project and workspaces
  • CI/CD if you want it (GitHub Actions boilerplate can be generated during aio app init)

Adobe manages after deploy:

  • Adobe I/O Runtime (serverless actions)
  • Hosted static assets from web-src (when you enable Web Assets)
  • Runtime scaling, namespaces, and the public URLs for deployed actions and SPAs

Your .env file and Runtime secrets stay out of Git. Your application logic, app.config.yaml, and action code go into Git like any other project. Adobe does not give you an "App Builder Git" product. You wire deployment yourself, or you use the generated GitHub Actions workflows.

Optional but common: connect the repo to a pipeline that runs aio login (or OAuth server-to-server credentials in CI) and then aio app deploy. That is still your pipeline on your infrastructure. Adobe only receives the built artifacts.


Before you install anything

You need App Builder entitlement on an IMS org, plus the Developer or System Administrator role in Adobe Admin Console (opens in new tab). Without that, Console will not offer the App Builder template and aio app init will not list your org.

If you are the org admin, Adobe's set-up guide walks through two Admin Console steps: create an App Builder product profile (any name works; Admin Console requires one before you can assign users), then add developers under Users → Developers and attach them to that profile. System Administrators get Console access without a separate product profile.

Local tooling from Adobe's set-up guide:

  • Node.js 18 or 20 (LTS; skip odd-numbered releases)
  • npm (ships with Node)
  • A terminal that works with the CLI's interactive prompts (Windows 10+, macOS 10.14+)
  • Optional: VS Code if you plan to use aio app dev with debugging

Install and update the AIO CLI

Install globally:

Run
npm install -g @adobe/aio-cli

Check version and update core plugins:

Run
aio -v
npm show @adobe/aio-cli version
aio update

If you already had an old install, run npm install -g @adobe/aio-cli again anyway. Adobe ships CLI changes on a fast cadence, and stale plugins cause weird aio app deploy failures that look like credential problems.

Log in:

Run
aio login

A browser window opens (or the CLI prints a URL). Sign in with the Adobe ID tied to the correct IMS org. The token is stored locally so later commands can talk to Console and Runtime.


AIO CLI commands you will actually use

The full command tree is huge. These are the ones I reach for on every project.

CommandWhat it does
aio loginAuthenticates the CLI with Adobe IMS
aio logoutClears stored credentials
aio whereShows current org, project, and workspace selection
aio console org listLists IMS orgs you can access
aio console org select <org>Switches active org
aio console project listLists projects in the selected org
aio console project select <project>Switches active project
aio console workspace listLists workspaces in the selected project
aio console workspace select <workspace>Switches active workspace
aio console workspace download [path]Downloads workspace config as JSON (legacy flows)
aio app init <name>Scaffolds a new App Builder app linked to Console
aio app useBinds the current folder to the selected workspace (writes .aio)
aio app use <path-to-json>Binds using a downloaded workspace config file
aio app devLocal dev server with hot reload
aio app buildBuilds actions and web assets without deploying
aio app deployDeploys actions and web assets to the bound workspace
aio app undeployRemoves deployed components from Runtime
aio app get-urlPrints URLs for deployed web assets and actions
aio templates discoverLists App Builder starter templates
aio templates install <package>Installs a template from the registry
aio openOpens Developer Console in the browser for the current org/project context

Add --help to any command when flags change between CLI versions. aio app deploy --help is worth reading once; you can deploy only actions or only web assets when you do not want a full redeploy.


What aio where is for

aio where is an alias for aio console where. It answers one question: "If I deploy right now, which org, project, and workspace am I hitting?"

Run
aio where

Example output shape:

text
Org: My Company IMS Org (1234567890ABCDEF@AdobeOrg)
Project: commerce-integrations (project-id-here)
Workspace: Stage

Run it from two places:

  1. Anywhere after you used aio console org select and friends. That sets a global CLI context.
  2. From the root of an App Builder app after aio app init or aio app use. The .aio file in the project overrides the global selection for deploy commands.

If aio where shows Production and you thought you were on a dev sandbox, stop. Fix the workspace before aio app deploy. I have seen teams push test actions to a production namespace because nobody ran aio where after switching laptops.

Machine-readable output for scripts:

Run
aio where --json
aio where --yml

Select org, project, and workspace from the CLI

After aio login, you can point the CLI at the Console project you just created without opening the browser again. This is the workflow Adobe documents for projects and workspaces (opens in new tab):

Run
aio login
aio where
 
aio console org list
aio console org select <org-id-or-name>
 
aio console project list
aio console project select <project-id-or-name>
 
aio console workspace list
aio console workspace select Stage
 
aio where

List commands accept partial names when you start typing in interactive mode. Once the global context is correct, cd into your app folder and run aio app use to write that binding into .aio.

If a teammate sent you a workspace export from Console (Download all on the workspace page), skip the select chain and bind directly:

Run
aio app use ./workspace-config.json

Create a Console project and pick a workspace

Do this in the browser first. The CLI can create projects (aio console project create), but the template flow in Console is easier the first time.

  1. Open Developer Console (opens in new tab) and select the correct IMS org.
  2. Click Quick Start, then Create project from template.
  3. Choose the App Builder template. If it is missing, your org lacks entitlement or you are in the wrong org.
  4. Set Project Title (human-readable) and App Name (immutable identifier). Leave Include Runtime with each workspace checked unless you have a specific reason not to.
  5. Save. You should see default workspaces Production and Stage.
  6. Open the workspace you will develop against (usually Stage for first experiments).
  7. Add APIs or Events only when you need them. A bare Hello World app does not require Commerce OAuth yet.

Back on your machine, bind the CLI to that workspace when you scaffold or clone:

Run
mkdir ~/app-builder-learning && cd ~/app-builder-learning
aio login
aio app init hello-world --standalone-app

The init wizard asks you to select org, project, and workspace. Type to filter long lists. When it finishes, it creates .aio, app.config.yaml, console.json, sample actions, and optionally web-src. Runtime values in .env are prepopulated from the workspace you picked.

Already have a folder and a downloaded workspace JSON from Console?

Run
cd hello-world
aio app use /path/to/workspace-config.json

Or, if your global CLI context is already correct:

Run
aio app use

Then confirm:

Run
aio where

Build a Hello World app from scratch

For lesson one, use the standalone empty project path. Extension-point templates add Commerce-specific scaffolding we do not need yet.

Run
aio app init hello-world --standalone-app

When prompted for Adobe I/O App features, enable at least:

  • Actions: Deploy Runtime actions
  • Web Assets: Deploy hosted static assets (so you get a visible UI)

For sample actions, pick Generic. For UI, React Spectrum 3 is the default Adobe pattern; Raw HTML/JS is fine if you want less React overhead.

After init, your folder should look roughly like this:

text
hello-world/
├── .aio                 # workspace binding (org, project, workspace ids)
├── .env                 # secrets for local run (gitignored)
├── app.config.yaml      # deploy manifest: actions, web assets, hooks
├── package.json
├── actions/
│   └── generic/
│       └── index.js     # sample Runtime action
├── web-src/
│   ├── index.html
│   └── src/             # React SPA source
├── test/
└── README.md

Open actions/generic/index.js. The generated handler usually returns JSON with a greeting. That is your serverless "backend." No Express server. No Magento bootstrap.

Run locally:

Run
aio app dev

The CLI prints local URLs for the SPA and action invocations. Change the greeting string, refresh, and confirm the loop works before you deploy anything.

On first run, the dev server may ask you to accept a self-signed certificate at https://localhost:9080. That is normal.

Adobe also documents aio app run for cases where you deploy actions to Runtime but serve the UI locally. For new projects, stay on aio app dev; it is the supported path with hot reload and VS Code debugging.


aio app use and the .aio file

aio app use connects your local directory to one Developer Console workspace. It writes or refreshes .aio with org, project, and workspace identifiers.

.aio stores org, project, and workspace IDs for the CLI. It is not a secrets file, but Adobe still recommends keeping it out of Git because it ties the repo to a specific Console workspace. Add .aio to .gitignore (the generator often does this for you) and regenerate it with aio app use after clone. CI pipelines should bind with aio app use or a workspace JSON instead of committing .aio.

console.json is the credential bundle downloaded during init or from Console's Download all button. It feeds both .aio and .env when you run aio app use <path-to-json> or aio app init --import <path-to-json>.

Typical flows:

Run
# Bind to currently selected console workspace
aio app use
 
# Bind using a JSON file exported from Console
aio app use ./console.json
 
# Verify binding
aio where

If deploy targets the wrong namespace, .aio is the first file I check.


The .env file

.env holds secrets for local development: Runtime auth, namespace, apihost, optional Commerce OAuth keys, third-party API tokens.

How the file appears:

  1. During aio app init, when you select a workspace with Runtime enabled, the CLI prepopulates AIO_runtime_* values from Console.
  2. During aio app use or aio app init --import <console.json>, Adobe copies workspace credentials into .env and .aio.
  3. When you add Commerce or other APIs later, append new keys to .env yourself. The env file tutorial (opens in new tab) shows the Commerce OAuth shape.

While aio app dev is running, the CLI may rewrite .env temporarily and restore your original file when you stop the process. Edit .env only when the dev server is stopped.

Rules:

  • Never commit .env to Git (add it to .gitignore; the generator usually does)
  • Regenerate or refresh when you rotate workspace credentials
  • For production secrets, use Runtime config or Adobe's secret mechanisms, not a checked-in file

Example shape (values are fake):

Run
# Specify your secrets here
# This file must not be committed to source control
 
## Adobe I/O Runtime credentials
AIO_runtime_auth=abcd1234-aaa-bbb-ccc-12345:secret-goes-here
AIO_runtime_namespace=12345-helloworld-stage
AIO_runtime_apihost=https://adobeioruntime.net
 
## Adobe I/O Console service account credentials (JWT) Api Key
SERVICE_API_KEY=

Actions receive these as params when invoked locally. In deployed Runtime, the same keys come from workspace configuration, not from your laptop's .env.


app.config.yaml

This file is the deploy manifest. It tells the CLI what to build, which packages to create in Runtime, and how web assets map to public paths.

Conceptually it has three jobs:

  1. Declare Runtime packages and actions (entry file, exposed web URL, limits)
  2. Declare static web assets from web-src after the build step
  3. Wire environment variables and annotations (concurrency, raw HTTP, etc.)

A minimal mental model:

yaml
application:
  actions: actions
  web: web-src
  runtimeManifest:
    packages:
      hello-world:
        license: Apache-2.0
        actions:
          generic:
            function: actions/generic/index.js
            web: 'yes'
            runtime: nodejs:18

The generator fills in more than this. Before you edit YAML by hand, read Adobe's app.config.yaml tutorial (opens in new tab) so you know how action names map to files under actions/.

If aio app deploy fails with "action not found" or "package missing," the bug is usually here, not in your JavaScript.

Environment placeholders in YAML (for example $SERVICE_API_KEY) resolve from .env at build/deploy time. They become action inputs in Runtime, not raw process.env inside deployed actions. Adobe's first-app docs call this out explicitly: do not read .env directly from action code in production.


The actions folder

Runtime code lives under actions/. Each subfolder is one action; app.config.yaml maps folder names to deployed functions.

For Hello World, you only need actions/generic/index.js. The handler exports main, uses @adobe/aio-sdk for logging, and returns an HTTP response object. That pattern is the same whether you later call Commerce REST, a third-party API, or nothing external at all.

Folder names are arbitrary but should stay readable. Adobe's Commerce samples use names like commerce/ for OAuth helpers shared across actions. When the app grows, keep one action per folder and let app.config.yaml stay the single deploy map.

Sample actions use CommonJS (require), not ES modules. Match that syntax unless Adobe docs for your CLI version say otherwise.


The web-src folder

Not every App Builder app needs a UI. Event-only integrations might be actions-only. When you do need an admin UI or operator dashboard, it lives under web-src.

Typical layout:

text
web-src/
├── index.html
├── exc.json              # Experience Cloud shell integration (when used)
└── src/
    ├── index.js          # React entry
    ├── components/
    └── utils/
        └── api.js        # calls your Runtime actions

The SPA builds to static files. Deploy uploads them next to your actions. aio app get-url shows the hosted URL after deploy.

Commerce samples often use React Spectrum (opens in new tab) components so the UI feels like other Adobe admin experiences. For Hello World, changing the heading in the default component is enough to prove the pipeline works.


Deploy with aio app deploy

From the app root (where app.config.yaml and .aio live):

Run
aio login
aio where
aio app deploy

Starting with AIO CLI v11, deploy uses Adobe IMS authentication. aio login (or CI OAuth server-to-server credentials) is required. Old Runtime namespace-only auth paths are gone.

Successful deploy prints action URLs and web asset URLs. You can also fetch them later:

Run
aio app get-url

Verify the hosted app three ways:

  1. CLI output right after deploy (web and action URLs)
  2. aio app get-url from the project root
  3. Developer Console → your project → workspace → Runtime / static assets overview (same URLs, useful when a teammate deployed and you only have Console access)

Open the web URL in a browser. You should see your Hello World UI served from Adobe's infrastructure, not localhost. Hit the generic action URL directly to confirm the backend responds with JSON.

Useful variants:

Run
# Deploy only actions
aio app deploy --actions
 
# Deploy only static web assets
aio app deploy --web-assets
 
# Tear down what this app deployed
aio app undeploy

Hitting workspace quotas or namespace limits shows up as Runtime errors during deploy, not as Git problems. Check Console usage if deploy suddenly fails after weeks of working fine.


Quick troubleshooting

Wrong workspace after clone: run aio app use and aio where again.

App Builder template missing in Console: wrong IMS org or missing Admin Console product profile.

Deploy auth errors: run aio login, confirm CLI v11+ behavior, and verify CI uses OAuth server-to-server if you are not interactive.

Local dev works, deploy fails: compare app.config.yaml action names to folders under actions/.

Blank UI after deploy: run aio app get-url and confirm web assets were included in the last deploy.


What to do next

You now have the full loop: Console project, local repo, CLI binding, local dev, deploy to Runtime, verify the hosted URL. Continue with Lesson 2: Call Adobe Commerce REST from an App Builder action (opens in new tab). Until then, change the generic action to return something dynamic (timestamp, workspace name) and redeploy once so the deploy step feels boring, which is the goal.

Further reading: