# Developing Apps Locally: New and Existing

> Source: https://agilitycms.com/docs/apps/developing-apps-locally-new-and-existing

Agility Apps run inside iframes in the CMS. That means your app needs to be reachable from a real URL. Not `http://localhost:3000`. The browser won't allow it, and neither will Agility.

This trips up every developer at least once. You scaffold your app, fire up `next dev`, point Agility at localhost, and nothing loads. No error message. Just a blank iframe.

Here's the deal. There are two scenarios, and each has a clean solution.

## Scenario 1: You're Building a Brand New App

You don't have a deployed URL yet. You just want to get something rendering inside the CMS so you can start building.

**Use ngrok.**

[ngrok](https://ngrok.com/) gives you a public HTTPS URL that tunnels traffic to your local machine. It takes about 30 seconds to set up.

### Steps

1. Install ngrok if you haven't already:

```bash
brew install ngrok
```

2. Start your app locally:

```bash
npm run dev
```

This runs on `http://localhost:3000` as usual.

3. In a separate terminal, start ngrok:

```bash
ngrok http 3000
```

4. ngrok gives you a URL like `https://abcd-1234.ngrok-free.app`. Copy it.

5. In Agility, register your app using that ngrok URL. Your `/.well-known/agility-app.json` file will be served through the tunnel, and all your app surfaces (custom fields, sidebars, dashboards, etc.) will load inside the CMS.

### Things to Know

- The ngrok URL changes every time you restart it (unless you're on a paid plan with reserved domains). You'll need to update your app registration in Agility each time.
- ngrok free tier shows an interstitial warning page on first load. This can interfere with the iframe. A paid plan removes that, or you can add the `ngrok-skip-browser-warning` header in your app.
- This is a **temporary** workflow. Once you're ready, deploy your app to a proper host (Vercel, Netlify, Cloudflare, wherever) and update your app registration to the real URL.

## Scenario 2: You're Updating an Existing Deployed App

Your app is already deployed and registered in Agility at something like `https://my-agility-app.vercel.app`. You want to make changes locally and see them in the CMS without deploying every time.

**Spoof the URL locally.**

The idea is simple. Run your app locally on HTTPS using the same domain as the deployed app, then redirect that domain to your local machine using your hosts file.

### Step 1: Run Next.js in HTTPS Mode

Next.js has built-in support for self-signed certificates in dev mode:

```bash
next dev --experimental-https
```

This starts your dev server at `https://localhost:3000` with a self-signed cert.

For more details, see [Vercel's guide on running Next.js with HTTPS locally](https://vercel.com/kb/guide/access-nextjs-localhost-https-certificate-self-signed).

### Step 2: Edit Your Hosts File

Your hosts file lets you override DNS for any domain on your machine. You're going to point your app's production domain to `127.0.0.1`.

On Mac/Linux, edit `/etc/hosts`:

```bash
sudo nano /etc/hosts
```

On Windows, edit `C:\Windows\System32\drivers\etc\hosts` (run your editor as Administrator).

Add a line like this:

```
127.0.0.1   my-agility-app.vercel.app
```

Replace `my-agility-app.vercel.app` with whatever domain your app is actually deployed to.

### Step 3: Accept the Self-Signed Certificate

Open `https://my-agility-app.vercel.app:3000` in your browser. You'll get a certificate warning because the self-signed cert doesn't match the domain. Click through and accept it.

**This step matters.** If you skip it, the iframe inside Agility will silently fail to load your app. The browser blocks untrusted certs in iframes without any visible error. Visit the URL directly first, accept the cert, then go back to Agility.

### Step 4: Load Your App in Agility

Now when Agility tries to load your app in an iframe, the browser resolves the domain to your local machine, and your local dev server responds. You get hot reload, console logs, the whole local dev experience, but running inside the CMS.

### When You're Done

Remove the hosts file entry. Otherwise your production app will stop working on your machine (because it'll keep resolving to localhost instead of the real server).

```
# 127.0.0.1   my-agility-app.vercel.app   <-- comment it out or delete it
```

## Quick Reference

| Situation | Solution | Complexity |
|---|---|---|
| New app, no deployed URL yet | ngrok tunnel to localhost | Low |
| Existing app, iterating on changes | HTTPS dev mode + hosts file spoof | Medium |

## Further Reading

- [Apps SDK Documentation](https://agilitycms.com/docs/apps/apps-sdk) for the full `@agility/app-sdk` reference
- [App Types in Agility](https://agilitycms.com/docs/apps/apps-in-agility) for marketplace vs. private apps
- [Creating Apps for Agility](https://agilitycms.com/docs/apps/creating-apps-for-agility)
