> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Started: Create Your First Application

> Create your first JavaScript hello world app in Bazel using the js starter repository, generating BUILD files with Gazelle and running it via bazel run.

Bazel handles JavaScript code, dependencies, and build configuration automatically. Before diving into the detailed part of the course, you'll build your first `Hello world` app.

## What you'll learn

* Setting up a development environment using a starter repository
* Generating dependency and executable targets with Gazelle
* Understanding how `npm_link_all_packages` and `js_binary` work together
* Building and running your first JavaScript application with Bazel

## Get started

The following steps will guide you through setting up your development environment and running your first Bazel app.

<Steps>
  <Step title="Setup a development environment" titleSize="h3">
    Navigate to the [aspect starter repository](https://github.com/aspect-starters/js), to access a ready to use developer environment already set up for you.

    <img src="https://mintcdn.com/aspectbuild/gtqBKXWWd-jWHweY/learning/bazel-105/starters-js.png?fit=max&auto=format&n=gtqBKXWWd-jWHweY&q=85&s=6a16e91b983902515e59b1f2705f5bd5" alt="starter" width="2364" height="1816" data-path="learning/bazel-105/starters-js.png" />

    <Note>
      The dev container doesn't have Node.js tooling installed globally.
      Bazel provides Node.js, pnpm, buildozer, ibazel and the other tools, and <code>bazel\_env.bzl</code> puts them on your <code>PATH</code> through <a href="https://direnv.net">direnv</a>.
      The Codespace runs <code>direnv allow</code> and <code>bazel run //tools:bazel\_env</code> for you when it starts. On your own machine, run those two commands once after cloning.
    </Note>
  </Step>

  <Step title="Create a project" titleSize="h3">
    Create a new project using one of these methods. Option A allows you to create a permanent project, while option B gives you a playground to experiment with.

    **Option A: Create a new repository**

    1. Click the **Use this template** green button at the top right corner of the starter repository
    2. Select **Create a new repository** from the dropdown menu
    3. Pick a name for your new repository
    4. Click **Create repository** - you'll be redirected to your new repository with the Bazel template
    5. Press `,` (comma key) to open the project in a GitHub Codespace

    <Info>
      GitHub Codespaces comes with Bazel preinstalled via [Bazelisk](https://bazel.build/install/bazelisk), so no manual Bazel installation is required.
    </Info>

    <img src="https://mintcdn.com/aspectbuild/gtqBKXWWd-jWHweY/snippets/createproject.gif?s=96f3dbe7515bd6f432dd2c9a00616937" alt="starter" width="2716" height="1406" data-path="snippets/createproject.gif" />

    **Option B: Test on a remote playground**

    1. Click the **Use this template** green button at the top right corner of the starter repository
    2. Select **Open in a codespace** to open the project directly

    Once you're in the codespace, wait a few minutes for the machine to boot up. Ignore any errors in the terminal - they will be resolved once all setup scripts complete.

    <Tip>By default, codespaces launch with a smaller machine. For a faster, more responsive development experience, [create a codespace with a larger machine](https://github.com/codespaces/new).</Tip>
  </Step>

  <Step title="Install VsCode extensions" titleSize="h3">
    Install the VS Code extension when prompted. This primarily gives you access to syntax highlighting in Bazel configurations.

    <img src="https://mintcdn.com/aspectbuild/gtqBKXWWd-jWHweY/learning/bazel-105/extensions.png?fit=max&auto=format&n=gtqBKXWWd-jWHweY&q=85&s=9ec37f1cb996825c1ba307e6781c65a0" alt="extensions" width="2734" height="1458" data-path="learning/bazel-105/extensions.png" />
  </Step>

  <Step title="Install packages & dependencies" titleSize="h3">
    1. Create the folders `packages/hello` in your project root folder. The starter ships its own sample under `hello/`, so `packages/` does not exist yet.

    ```bash theme={null}
    mkdir -p packages/hello
    ```

    2. Navigate to the `hello` folder

    ```bash theme={null}
    cd packages/hello
    ```

    3. Initialize the package

    ```bash theme={null}
    pnpm init
    ```

    4. Set the package to use the ESM module syntax ("import" rather than "require")

    ```bash theme={null}
    pnpm pkg set type=module
    ```

    5. Install **chalk** so it's ready to use by running

    ```bash theme={null}
    pnpm add chalk
    ```

    <Note>The <code>pnpm-workspace.yaml</code> file at the repository root lists <code>packages/\*</code>, so every folder created under <code>packages</code> is treated as a local monorepo package.</Note>
  </Step>

  <Step title="Create the app" titleSize="h3">
    1. Create an `index.js` file in the `hello` folder.
    2. Paste this code in your `index.js` file.

    ```javascript theme={null}
    import chalk from 'chalk';
    console.log(chalk.green('Hello World!'));
    ```

    3. Add a shortcut to your package.json file, to test the program with plain Node.js first.

    ```bash theme={null}
    pnpm pkg set scripts.hello="node index.js"
    ```

    4. Run the app to test that the program works with Node.js alone.

    ```bash theme={null}
    pnpm run hello
    ```

    You should see `Hello World!` printed out in the terminal in green.

    ```
    > hello@1.0.0 hello /workspaces/js/packages/hello
    > node index.js

    Hello World!
    ```

    Now proceed to running the app with Bazel.
  </Step>

  <Step title="Generate the Build file" titleSize="h3">
    Run the command below from the Bazel module root to generate the `BUILD` file using [Gazelle](https://github.com/bazel-contrib/bazel-gazelle). Bazel needs this declarative file to understand the application's inputs and dependencies.

    ```bash theme={null}
    aspect gazelle
    ```

    Gazelle creates `packages/hello/BUILD.bazel`. The starter's Orion extension recognizes the `hello` script you added earlier and generates the `js_binary` alongside the dependency links. The completed file should be:

    ```python theme={null}
    load("@aspect_rules_js//js:defs.bzl", "js_binary")
    load("@npm//:defs.bzl", "npm_link_all_packages")

    npm_link_all_packages(name = "node_modules")

    js_binary(
        name = "hello",
        data = [
            "package.json",
            ":node_modules",
        ],
        entry_point = "index.js",
    )
    ```

    `npm_translate_lock` in `MODULE.bazel` has already converted the pnpm lockfile into targets in the external `@npm` repository. `npm_link_all_packages` selects the packages needed here and exposes them through the package-local `node_modules` target.

    `js_binary` then creates a hermetic launcher for `index.js`. Its `data` attribute defines the runtime files: the package metadata and linked npm dependencies. Undeclared files are not silently available, which keeps execution reproducible and cacheable.

    <Note>
      The `hello` script must have the simple form <code>node \<file></code> for the starter's Orion extension to infer a binary. Other script forms are skipped; for those, declare the appropriate <code>rules\_js</code> target directly.
    </Note>

    <Note>
      This works for simple flat package structures. For projects using `tsconfig` `outDir` or `rootDir` to manipulate output paths, you'll most likely want to add `# gazelle:generation_mode update_only` to a parent `BUILD` file and create `BUILD` files manually at the package level. The next guide covers this.
    </Note>
  </Step>

  <Step title="Run the program with Bazel" titleSize="h3">
    1. Run this command to verify that the app runs with Bazel. You should see `Hello World` printed on the terminal. The label `//packages/hello` is short for `//packages/hello:hello`, the `js_binary` target Gazelle generated.

    ```bash theme={null}
    bazel run //packages/hello
    ```

    2. Return to the package, then add a shortcut to its `package.json` so you can run the program without typing the full label.

    ```bash theme={null}
    cd packages/hello
    pnpm pkg set scripts.start="bazel run //packages/hello"
    ```

    3. Run the program

    ```bash theme={null}
    pnpm start
    ```

    Bazel analyzes the target, builds it, and runs the result:

    ```
    > hello@1.0.0 start /workspaces/js/packages/hello
    > bazel run //packages/hello

    INFO: Analyzed target //packages/hello:hello (1 packages loaded, 7 targets configured).
    INFO: Found 1 target...
    Target //packages/hello:hello up-to-date:
      bazel-bin/packages/hello/hello_/hello
    INFO: Build completed successfully, 10 total actions
    INFO: Running command line: bazel-bin/packages/hello/hello_/hello
    Hello World!
    ```

    That’s it, you've successfully built and run a basic JavaScript app with Bazel.
  </Step>
</Steps>

## What’s next

The next guide, **TypeScript and Web**, introduces a browser-based app, TypeScript, and monorepo package dependencies.
