# How to Add a New Built-in dApp to Nautilus Wallet: 6-Step Implementation Guide

> Learn to add a new built-in dApp to Nautilus Wallet with our 6-step guide. Implement Vue components, register dApps, and add routes easily.

- Repository: [Nautilus Team/nautilus-wallet](https://github.com/nautls/nautilus-wallet)
- Tags: how-to-guide
- Published: 2026-03-07

---

**To add a new built-in dApp to Nautilus Wallet, create a Vue component in `src/dapps/`, register the dApp in [`src/dapps/dappsManifest.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/dappsManifest.ts), and add a route in [`src/extension/popup/router.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/extension/popup/router.ts) after providing translations and an icon.**

Nautilus Wallet is an open-source browser extension wallet for the Ergo blockchain that ships with built-in dApps like SigmaUSD and Wallet Optimizer. If you are contributing to the `nautls/nautilus-wallet` repository, adding a new built-in dApp to Nautilus Wallet follows a predictable pipeline that integrates your component into the existing Vue 3 architecture.

## Prerequisites and Overview

Before adding a built-in dApp, ensure you have the repository cloned and dependencies installed (`pnpm install`). The wallet uses Vue 3 with TypeScript, Vue Router, and Lucide icons. Built-in dApps are not external websites; they are first-party Vue components rendered inside the wallet's popup interface.

The process involves six distinct steps: creating the UI component, adding translation keys, providing an icon, registering in the manifest, configuring the router, and optionally adding tests.

## Step-by-Step Process for Adding a Built-in dApp

### 1. Create the dApp UI Component

Create a new directory under `src/dapps/` containing your Vue single-file component. Use the existing built-in dApps as templates.

```vue
<!-- src/dapps/my-dapp/MyDappView.vue -->
<script setup lang="ts">
import { ref } from "vue";

const message = ref("Hello from My dApp!");
</script>

<template>
  <div class="p-4">
    <h2 class="text-xl font-bold">{{ message }}</h2>
    <!-- dApp-specific UI goes here -->
  </div>
</template>

<style scoped>
/* optional component-scoped CSS */
</style>

```

The component is lazy-loaded by the router, so you can import services, composables, or heavy libraries without impacting initial load time. Reference [`src/dapps/sigma-usd/SigmaUSDView.vue`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/sigma-usd/SigmaUSDView.vue) or [`src/dapps/wallet-optimization/WalletOptimizationDApp.vue`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/wallet-optimization/WalletOptimizationDApp.vue) for production patterns.

### 2. Add Translation Entries

Add a title key for your dApp in every locale file under `src/i18n/locales/`. At minimum, update [`en-US.json`](https://github.com/nautls/nautilus-wallet/blob/main/en-US.json).

```json
// src/i18n/locales/en-US.json
{
  "dapps": {
    "myDapp": {
      "title": "My Awesome dApp"
    }
  }
}

```

Repeat this entry in all supported locale files (e.g., [`es.json`](https://github.com/nautls/nautilus-wallet/blob/main/es.json), [`ru.json`](https://github.com/nautls/nautilus-wallet/blob/main/ru.json)). The `tileKeypath` in the manifest will reference this key as `myDapp.title`.

### 3. Provide an Icon

You have two options for the dApp tile icon:

**Option A: SVG Asset**

Place an SVG file in your dApp directory and import it as a Vue component:

```ts
// In src/dapps/dappsManifest.ts
import MyDappLogo from "./my-dapp/my-dapp-logo.svg";

```

**Option B: Lucide Icon**

Import any icon from the `lucide-vue-next` library:

```ts
import { Coffee } from "lucide-vue-next";

```

The icon must be a Vue component that can be rendered dynamically with `<component :is="...">`.

### 4. Register the dApp in the Manifest

Open [`src/dapps/dappsManifest.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/dappsManifest.ts) and add your dApp to the `dappsManifest` array. Use the `component()` helper defined in the same file to wrap your icon.

```ts
// src/dapps/dappsManifest.ts
import { component } from "./dappsManifest"; // helper function
import MyDappLogo from "./my-dapp/my-dapp-logo.svg";

export const dappsManifest: DAppManifestItem[] = [
  // ...existing entries (SigmaUSD, Wallet Optimizer)
  {
    tileKeypath: "myDapp.title",      // matches translation key
    icon: component(MyDappLogo),       // or component(Coffee, { size: 24 })
    path: "/dapps/my-dapp"            // URL route
  }
];

```

The manifest drives the tile grid displayed in [`src/views/dapps/DappsList.vue`](https://github.com/nautls/nautilus-wallet/blob/main/src/views/dapps/DappsList.vue). Each entry automatically generates a clickable card that navigates to the specified path.

### 5. Add the Router Entry

Expose your component under `/dapps/<path>` by adding a child route in [`src/extension/popup/router.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/extension/popup/router.ts). Insert the object into the `children` array of the `/dapps` route (around lines 60-68).

```ts
// src/extension/popup/router.ts
{
  path: "my-dapp",
  name: "my-dapp",
  component: () => import("@/dapps/my-dapp/MyDappView.vue")
}

```

The router automatically constructs the full path `/dapps/my-dapp`, which must match the `path` declared in the manifest. The lazy-load function ensures the component code is only fetched when the user navigates to the dApp.

### 6. (Optional) Add Tests and Documentation

Maintain code quality by adding unit tests under `tests/unit/` that mount your component and verify basic rendering. If your dApp exposes a public API for other connectors, document it in `docs/dapp-connector/`.

## Complete Working Example

Here is the minimal set of changes required to add a dApp named "Portfolio Tracker":

**Translation** ([`src/i18n/locales/en-US.json`](https://github.com/nautls/nautilus-wallet/blob/main/src/i18n/locales/en-US.json)):

```json
{
  "dapps": {
    "portfolioTracker": {
      "title": "Portfolio Tracker"
    }
  }
}

```

**Manifest** ([`src/dapps/dappsManifest.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/dappsManifest.ts)):

```ts
import { component } from "./dappsManifest";
import PortfolioIcon from "./portfolio-tracker/portfolio-icon.svg";

export const dappsManifest: DAppManifestItem[] = [
  {
    tileKeypath: "portfolioTracker.title",
    icon: component(PortfolioIcon),
    path: "/dapps/portfolio-tracker"
  }
];

```

**Router** ([`src/extension/popup/router.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/extension/popup/router.ts)):

```ts
{
  path: "portfolio-tracker",
  name: "portfolio-tracker",
  component: () => import("@/dapps/portfolio-tracker/PortfolioTrackerView.vue")
}

```

After running `pnpm dev`, the "Portfolio Tracker" tile appears in the dApps gallery and navigates to your component.

## Key Files Reference

| Purpose | File Path | Source Link |
|---------|-----------|-------------|
| dApp manifest registry | [`src/dapps/dappsManifest.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/dappsManifest.ts) | [View on GitHub](https://github.com/nautls/nautilus-wallet/blob/master/src/dapps/dappsManifest.ts#L26-L37) |
| Popup router configuration | [`src/extension/popup/router.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/extension/popup/router.ts) | [View on GitHub](https://github.com/nautls/nautilus-wallet/blob/master/src/extension/popup/router.ts#L60-L68) |
| dApp list UI (tile grid) | [`src/views/dapps/DappsList.vue`](https://github.com/nautls/nautilus-wallet/blob/main/src/views/dapps/DappsList.vue) | [View on GitHub](https://github.com/nautls/nautilus-wallet/blob/master/src/views/dapps/DappsList.vue) |
| Translation files | `src/i18n/locales/*.json` | [View en-US](https://github.com/nautls/nautilus-wallet/blob/master/src/i18n/locales/en-US.json#L326-L345) |
| Example: SigmaUSD dApp | [`src/dapps/sigma-usd/SigmaUSDView.vue`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/sigma-usd/SigmaUSDView.vue) | [View on GitHub](https://github.com/nautls/nautilus-wallet/blob/master/src/dapps/sigma-usd/SigmaUSDView.vue) |
| Example: Wallet Optimizer | [`src/dapps/wallet-optimization/WalletOptimizationDApp.vue`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/wallet-optimization/WalletOptimizationDApp.vue) | [View on GitHub](https://github.com/nautls/nautilus-wallet/blob/master/src/dapps/wallet-optimization/WalletOptimizationDApp.vue) |

## Summary

- **Create** a Vue 3 component under `src/dapps/<your-dapp>/` to house the user interface.
- **Translate** by adding a title key under `dapps.<name>.title` in every locale file.
- **Icon** your dApp using either an SVG import or a `lucide-vue-next` component.
- **Register** the dApp in [`src/dapps/dappsManifest.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/dappsManifest.ts) with `tileKeypath`, `icon`, and `path`.
- **Route** the component in [`src/extension/popup/router.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/extension/popup/router.ts) as a child of `/dapps` with matching path.
- **Test** your implementation by running `pnpm dev` and verifying the tile appears in the dApps gallery.

## Frequently Asked Questions

### Do I need to manually update the dApps list view to show my new tile?

No. The [`DappsList.vue`](https://github.com/nautls/nautilus-wallet/blob/main/DappsList.vue) component automatically renders tiles based on the `dappsManifest` array defined in [`src/dapps/dappsManifest.ts`](https://github.com/nautls/nautilus-wallet/blob/main/src/dapps/dappsManifest.ts). As long as you register your dApp in the manifest with a valid `tileKeypath` and `icon`, the UI will display it without additional changes to the list view component.

### Can I use external npm libraries in my built-in dApp?

Yes. Since built-in dApps are standard Vue 3 components, you can import external libraries from npm. The component is lazy-loaded via the router's dynamic import, so heavy dependencies will only be fetched when the user navigates to your dApp. Follow the existing patterns in [`SigmaUSDView.vue`](https://github.com/nautls/nautilus-wallet/blob/main/SigmaUSDView.vue) for service integration.

### How do I handle state management within a built-in dApp?

Built-in dApps can use Vue's Composition API with `ref` and `reactive` for local state, or integrate with the wallet's existing composables located in the `src/composables/` directory. For global state shared across the extension, import the relevant stores from `src/stores/`. The Wallet Optimizer dApp demonstrates complex state synchronization with the wallet's UTXO set.

### What is the difference between a built-in dApp and a connected dApp?

Built-in dApps are first-party Vue components bundled directly into the extension source code and rendered inside the wallet's popup UI. Connected dApps are external websites that communicate with the wallet via the dApp Connector API (ERG-47). Built-in dApps have full access to internal services and don't require connection permissions, while connected dApps operate in a sandboxed browser context.